From 9a2b04c94b73ac0bdd97971732c40956efaaf189 Mon Sep 17 00:00:00 2001 From: David Liebeherr Date: Thu, 27 Aug 2026 06:57:09 +0200 Subject: [PATCH 01/12] build: reorganize .editorconfig and switch to C# keywords Groups the settings by concern, adds the missing [*] section, drops the UTF-8 BOM, and reverses the type-name rule: dotnet_style_predefined_type_for_* go to error, so `string` and `int` replace `String` and `Int32`. Also removes the IDE0290 suppression, which contradicted csharp_style_prefer_primary_constructors in the same file. The code catches up in the next two commits. Part of #21 Co-Authored-By: Claude Opus 5 --- .editorconfig | 317 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 227 insertions(+), 90 deletions(-) diff --git a/.editorconfig b/.editorconfig index 642ed7f..8ab2675 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,47 +1,148 @@ -root = true +root = true + +# ====================================================================================================== +# Every file +# +# Line endings are deliberately NOT set here. .gitattributes owns them: it normalizes to LF in the +# repository and checks each file out with the ending that file type needs. An end_of_line here would +# fight that on Windows. +# ====================================================================================================== + +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true + +# MSBuild and project files are tab-indented, which is what is already in the repository. +[*.{csproj,props,targets,slnx,config,resx,DotSettings}] +indent_style = tab +tab_width = 4 + +[*.{json,yml,yaml}] +indent_size = 2 + +# Two trailing spaces are a hard line break in Markdown, so they must survive. +[*.md] +trim_trailing_whitespace = false + +[*.ps1] +end_of_line = crlf + +# ====================================================================================================== +# C# +# +# Three tools share this file, and each one owns exactly one concern: +# +# CSharpier whitespace, line breaks, wrapping. Reads max_line_length and indent_size. +# Roslyn analyzers code style (the settings below). Fixed by `dotnet format style`. +# NewStyleCop.Analyzers member ordering (checking only). Fixed by ReSharper, see the ordering +# section further down. +# +# Run scripts/tidy-cs.ps1 to apply all three. +# ====================================================================================================== [*.cs] + +#### Layout #### + +indent_size = 4 +tab_width = 4 + +# CSharpier reads this as its print width. It is the ONLY place the line width is configured. max_line_length = 120 -charset = utf-8 -csharp_using_directive_placement = outside_namespace:error -csharp_prefer_simple_using_statement = true:suggestion -csharp_prefer_braces = true:error -csharp_style_namespace_declarations = file_scoped:error -csharp_style_prefer_method_group_conversion = true:suggestion -csharp_style_prefer_top_level_statements = true:suggestion -csharp_style_prefer_primary_constructors = true:error -csharp_prefer_system_threading_lock = false:silent -csharp_style_prefer_simple_property_accessors = true:error -csharp_style_expression_bodied_methods = true:error +#### Types: C# keywords, never BCL type names #### + +# `string`, `int`, `bool` - not `String`, `Int32`, `Boolean`. Both settings are IDE0049. +dotnet_style_predefined_type_for_locals_parameters_members = true:error +dotnet_style_predefined_type_for_member_access = true:error + +# `var` wherever the type is obvious from the right-hand side. +csharp_style_var_for_built_in_types = true:error +csharp_style_var_when_type_is_apparent = true:error + +#### Member access: always `this.` #### + +# Instance members are always read and written through `this.`, and fields are never `_camelCase`. +# Primary constructor parameters are the one thing this does not cover, and that is not an exception: +# in C# they are parameters, not instance members, so `this.` cannot be applied to them at all. +dotnet_style_qualification_for_event = true:error +dotnet_style_qualification_for_field = true:error +dotnet_style_qualification_for_method = true:error +dotnet_style_qualification_for_property = true:error + +#### Expression-bodied members #### + +# Use `=>` wherever a member is a single expression. +csharp_style_expression_bodied_accessors = true:error csharp_style_expression_bodied_constructors = true:error -csharp_style_expression_bodied_operators = true:error -csharp_style_expression_bodied_properties = true:error csharp_style_expression_bodied_indexers = true:error -csharp_style_expression_bodied_accessors = true:error csharp_style_expression_bodied_lambdas = true:error csharp_style_expression_bodied_local_functions = true:error -csharp_style_throw_expression = true:error -csharp_style_prefer_null_check_over_type_check = true:error +csharp_style_expression_bodied_methods = true:error +csharp_style_expression_bodied_operators = true:error +csharp_style_expression_bodied_properties = true:error +csharp_style_prefer_simple_property_accessors = true:error + +#### Namespaces and using directives #### + +csharp_style_namespace_declarations = file_scoped:error +csharp_using_directive_placement = outside_namespace:error +dotnet_style_namespace_match_folder = true:error + +#### Declarations #### + +csharp_prefer_braces = true:error +csharp_style_prefer_primary_constructors = true:error +csharp_style_prefer_top_level_statements = true:suggestion +dotnet_style_prefer_auto_properties = true:error + +#### Modern language features #### + csharp_prefer_simple_default_expression = true:error -csharp_style_prefer_local_over_anonymous_function = true:suggestion -csharp_style_prefer_index_operator = true:error +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_system_threading_lock = false:silent csharp_style_implicit_object_creation_when_type_is_apparent = true:error +csharp_style_inlined_variable_declaration = true:error csharp_style_prefer_implicitly_typed_lambda_expression = true:error -csharp_style_prefer_unbound_generic_type_in_nameof = true:error +csharp_style_prefer_index_operator = true:error +csharp_style_prefer_local_over_anonymous_function = true:suggestion +csharp_style_prefer_method_group_conversion = true:suggestion csharp_style_prefer_not_pattern = true:error -csharp_style_var_for_built_in_types = true:error -csharp_style_var_when_type_is_apparent = true:error csharp_style_prefer_range_operator = true:error csharp_style_prefer_tuple_swap = true:error +csharp_style_prefer_unbound_generic_type_in_nameof = true:error csharp_style_prefer_utf8_string_literals = true:error -csharp_style_inlined_variable_declaration = true:error +csharp_style_throw_expression = true:error +dotnet_style_collection_initializer = true:suggestion +dotnet_style_object_initializer = true:suggestion +dotnet_style_prefer_collection_expression = when_types_loosely_match:error +dotnet_style_prefer_compound_assignment = true:error +dotnet_style_prefer_simplified_interpolation = true:error + +#### Null handling #### + +csharp_style_prefer_null_check_over_type_check = true:error +dotnet_style_coalesce_expression = true:error +dotnet_style_null_propagation = true:error +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:error + +#### Expressions #### + csharp_style_deconstructed_variable_declaration = true:suggestion csharp_style_unused_value_assignment_preference = discard_variable:error csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion -dotnet_analyzer_diagnostic.category-roslynator.severity = error +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_return = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:error +dotnet_style_prefer_inferred_tuple_names = true:error +dotnet_style_prefer_simplified_boolean_expressions = true:error -#### Naming styles #### +#### Naming #### # Naming rules @@ -49,14 +150,9 @@ dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i -dotnet_naming_style.pascal_with_underscores.capitalization = pascal_case -dotnet_naming_style.pascal_with_underscores.required_prefix = -dotnet_naming_style.pascal_with_underscores.required_suffix = -dotnet_naming_style.pascal_with_underscores.word_separator = _ - +dotnet_naming_rule.types_should_be_pascal_with_underscores.severity = warning dotnet_naming_rule.types_should_be_pascal_with_underscores.symbols = types dotnet_naming_rule.types_should_be_pascal_with_underscores.style = pascal_with_underscores -dotnet_naming_rule.types_should_be_pascal_with_underscores.severity = warning dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members @@ -66,73 +162,105 @@ dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case dotnet_naming_symbols.interface.applicable_kinds = interface dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.interface.required_modifiers = +dotnet_naming_symbols.interface.required_modifiers = dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.types.required_modifiers = +dotnet_naming_symbols.types.required_modifiers = dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.non_field_members.required_modifiers = +dotnet_naming_symbols.non_field_members.required_modifiers = # Naming styles dotnet_naming_style.begins_with_i.required_prefix = I -dotnet_naming_style.begins_with_i.required_suffix = -dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = dotnet_naming_style.begins_with_i.capitalization = pascal_case -dotnet_naming_style.pascal_case.required_prefix = -dotnet_naming_style.pascal_case.required_suffix = -dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = dotnet_naming_style.pascal_case.capitalization = pascal_case -dotnet_style_operator_placement_when_wrapping = beginning_of_line -tab_width = 4 -indent_size = 4 -dotnet_style_coalesce_expression = true:error -dotnet_style_null_propagation = true:error -dotnet_style_prefer_is_null_check_over_reference_equality_method = true:error -dotnet_style_prefer_auto_properties = true:error -dotnet_style_object_initializer = true:suggestion -dotnet_style_collection_initializer = true:suggestion -dotnet_style_prefer_simplified_boolean_expressions = true:error -dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion -dotnet_style_prefer_conditional_expression_over_return = true:suggestion -dotnet_style_explicit_tuple_names = true:suggestion -dotnet_style_prefer_inferred_tuple_names = true:error -dotnet_style_prefer_inferred_anonymous_type_member_names = true:error -dotnet_style_prefer_compound_assignment = true:error -dotnet_style_prefer_simplified_interpolation = true:error -dotnet_style_prefer_collection_expression = when_types_loosely_match:error -dotnet_style_namespace_match_folder = true:error -dotnet_style_predefined_type_for_locals_parameters_members = false:silent -dotnet_style_predefined_type_for_member_access = false:silent +dotnet_naming_style.pascal_with_underscores.required_prefix = +dotnet_naming_style.pascal_with_underscores.required_suffix = +dotnet_naming_style.pascal_with_underscores.word_separator = _ +dotnet_naming_style.pascal_with_underscores.capitalization = pascal_case + +#### Formatting is CSharpier's job #### -# RCS1037: Remove trailing white-space +# IDE0055 is "fix formatting" - every whitespace rule Roslyn has, under one ID. A number of its options +# disagree with CSharpier, and CSharpier is the tool that owns whitespace here, so this stays off. +# CSharpier's own documentation recommends exactly this. +dotnet_diagnostic.IDE0055.severity = none + +# RCS1037: Remove trailing white-space. Same reason - CSharpier removes it, and trim_trailing_whitespace +# in the [*] section above tells the editor to. dotnet_diagnostic.RCS1037.severity = none -# RCS1227: Validate arguments correctly -dotnet_diagnostic.RCS1227.severity = none +#### Member ordering: NewStyleCop.Analyzers #### -# RCS1124: Inline local variable -dotnet_diagnostic.RCS1124.severity = suggestion +# StyleCop is here for ONE job: reporting types and members that are in the wrong order. Everything else +# it does is either CSharpier's concern or already covered by the Roslyn, Roslynator and Sonar rules in +# this file, so every category is switched off first and only the rules we want are switched back on. +# Adding a StyleCop rule to this repository means adding it explicitly below. +# +# StyleCop can only REPORT a wrong order - its ordering code fix is disabled upstream. ReSharper does the +# fixing: in Rider through Code Cleanup, and on the command line through scripts/tidy-cs.ps1. So the +# order is defined twice, and the two definitions have to stay in step: +# stylecop.json -> what is checked +# DbConnectionPlus.slnx.DotSettings -> what is applied +dotnet_analyzer_diagnostic.category-StyleCop.CSharp.DocumentationRules.severity = none +dotnet_analyzer_diagnostic.category-StyleCop.CSharp.LayoutRules.severity = none +dotnet_analyzer_diagnostic.category-StyleCop.CSharp.MaintainabilityRules.severity = none +dotnet_analyzer_diagnostic.category-StyleCop.CSharp.NamingRules.severity = none +dotnet_analyzer_diagnostic.category-StyleCop.CSharp.OrderingRules.severity = none +dotnet_analyzer_diagnostic.category-StyleCop.CSharp.ReadabilityRules.severity = none +dotnet_analyzer_diagnostic.category-StyleCop.CSharp.SpacingRules.severity = none +dotnet_analyzer_diagnostic.category-StyleCop.CSharp.SpecialRules.severity = none -# IDE0290: Use primary constructor -dotnet_diagnostic.IDE0290.severity = none +# SA1201: Elements should appear in the correct order (by kind). +dotnet_diagnostic.SA1201.severity = error -# CA2100: Review SQL queries for security vulnerabilities -dotnet_diagnostic.CA2100.severity = none +# SA1202: Elements should be ordered by access. +dotnet_diagnostic.SA1202.severity = error + +# SA1203: Constants should appear before fields. +dotnet_diagnostic.SA1203.severity = error + +# SA1204: Static elements should appear before instance elements. +dotnet_diagnostic.SA1204.severity = error + +# SA1214: Readonly fields should appear before non-readonly fields. +dotnet_diagnostic.SA1214.severity = error + +# SA1309: Field names should not begin with an underscore. Nothing else enforces this, and it is the +# other half of the "always `this.`" decision - see the member access section above. +dotnet_diagnostic.SA1309.severity = error + +#### Roslynator #### + +dotnet_analyzer_diagnostic.category-roslynator.severity = error + +# RCS1124: Inline local variable +dotnet_diagnostic.RCS1124.severity = suggestion # RCS1222: Merge preprocessor directives dotnet_diagnostic.RCS1222.severity = none +# RCS1227: Validate arguments correctly +dotnet_diagnostic.RCS1227.severity = none + # RCS1237: Use bit shift operator dotnet_diagnostic.RCS1237.severity = none -# xUnit1051: Calls to methods which accept CancellationToken should use TestContext.Current.CancellationToken -dotnet_diagnostic.xUnit1051.severity = none +#### .NET analyzers #### + +# CA2100: Review SQL queries for security vulnerabilities +# Running SQL the caller wrote is what this library does. Same reason S2077 is off below. +dotnet_diagnostic.CA2100.severity = none #### SonarAnalyzer.CSharp #### @@ -142,6 +270,16 @@ dotnet_diagnostic.xUnit1051.severity = none # The two hits are deliberate pseudo-code explaining the expression trees the materializer factories emit. dotnet_diagnostic.S125.severity = none +# S2077: Formatting SQL queries is security-sensitive +# The temporary table builders emit DDL, where a table or column name can never be a bound parameter. Same +# reason CA2100 is off above; the identifiers are quoted per adapter, not interpolated user input. +dotnet_diagnostic.S2077.severity = none + +# S2325: Methods and properties that don't access instance data should be static +# CA1822 already covers this and correctly skips public members. S2325 does not: both hits are shipped public +# API listed in PublicAPI.Shipped.txt, where going static is a breaking change. +dotnet_diagnostic.S2325.severity = none + # S3011: Reflection should not be used to increase accessibility of classes, methods, or fields # Binding non-public constructors and members is what an entity materializer does; the sites are documented. dotnet_diagnostic.S3011.severity = none @@ -158,35 +296,34 @@ dotnet_diagnostic.S3881.severity = none # The generic throw helpers name the CALLER's parameter, which by design is not in their own signature. dotnet_diagnostic.S3928.severity = none -# S2077: Formatting SQL queries is security-sensitive -# The temporary table builders emit DDL, where a table or column name can never be a bound parameter. Same -# reason CA2100 is off above; the identifiers are quoted per adapter, not interpolated user input. -dotnet_diagnostic.S2077.severity = none - -# S2325: Methods and properties that don't access instance data should be static -# CA1822 already covers this and correctly skips public members. S2325 does not: both hits are shipped public -# API listed in PublicAPI.Shipped.txt, where going static is a breaking change. -dotnet_diagnostic.S2325.severity = none - # S4456: Parameter validation in yielding methods should be wrapped # The public Query overloads validate their arguments inside the iterator, so the exception surfaces on the # first MoveNext instead of at the call. Fixing it means splitting four public methods. dotnet_diagnostic.S4456.severity = none -[*.ps1] -end_of_line = crlf +#### xUnit #### + +# xUnit1051: Calls to methods which accept CancellationToken should use TestContext.Current.CancellationToken +dotnet_diagnostic.xUnit1051.severity = none + +# ====================================================================================================== +# Tests and benchmarks +# +# Held to the same style, formatting and ordering as the shipping libraries. What they are NOT held to is +# a handful of Sonar rules that only make sense for library code. +# ====================================================================================================== [{tests,benchmarks}/**/*.cs] +dotnet_diagnostic.S1144.severity = none +dotnet_diagnostic.S1172.severity = none dotnet_diagnostic.S2344.severity = none +dotnet_diagnostic.S2696.severity = none +dotnet_diagnostic.S2925.severity = none dotnet_diagnostic.S3010.severity = none -dotnet_diagnostic.S4144.severity = none -dotnet_diagnostic.S3459.severity = none dotnet_diagnostic.S3453.severity = none -dotnet_diagnostic.S1144.severity = none -dotnet_diagnostic.S1172.severity = none +dotnet_diagnostic.S3459.severity = none dotnet_diagnostic.S3963.severity = none -dotnet_diagnostic.S6562.severity = none -dotnet_diagnostic.S2925.severity = none +dotnet_diagnostic.S4144.severity = none dotnet_diagnostic.S5034.severity = none -dotnet_diagnostic.S2696.severity = none +dotnet_diagnostic.S6562.severity = none From 89bc6d82d1dcb8033083af45553d32d06cbc6fd8 Mon Sep 17 00:00:00 2001 From: David Liebeherr Date: Sun, 23 Aug 2026 03:32:14 +0200 Subject: [PATCH 02/12] style: use C# keywords instead of BCL type names Mechanical. Applied with: dotnet format style DbConnectionPlus.slnx --diagnostics IDE0049 String becomes string, Int32 becomes int, Boolean becomes bool, and so on, in declarations and in static member access alike. 7655 diagnostics across 207 files. No hand edits: the only non-rename change in the tree was the .editorconfig commit before this one. Cref references in XML documentation are untouched. IDE0049 does not rewrite them, and resolves the same either way. This commit is listed in .git-blame-ignore-revs. Part of #21 Co-Authored-By: Claude Opus 5 --- .../AotJobFilter.cs | 6 +- .../Benchmarks.DeleteEntities.cs | 6 +- .../Benchmarks.DeleteEntity.cs | 4 +- .../Benchmarks.ExecuteNonQuery.cs | 2 +- .../Benchmarks.ExecuteReader.cs | 2 +- .../Benchmarks.ExecuteScalar.cs | 14 +- .../Benchmarks.Exists.cs | 8 +- .../Benchmarks.InsertEntities.cs | 10 +- .../Benchmarks.InsertEntity.cs | 6 +- .../Benchmarks.Parameter.cs | 14 +- .../Benchmarks.Query_Dynamic.cs | 16 +- .../Benchmarks.Query_Entities.cs | 4 +- .../Benchmarks.Query_Scalars.cs | 16 +- .../Benchmarks.Query_ValueTuples.cs | 16 +- ...enchmarks.TemporaryTable_ComplexObjects.cs | 10 +- .../Benchmarks.TemporaryTable_ScalarValues.cs | 20 +- .../Benchmarks.UpdateEntities.cs | 10 +- .../Benchmarks.UpdateEntity.cs | 8 +- .../DbConnectionPlus.Benchmarks/Benchmarks.cs | 16 +- .../BenchmarksConfig.cs | 6 +- .../BenchmarksOrderer.cs | 14 +- .../DbConnectionPlus.Benchmarks/Program.cs | 2 +- .../TestData/BenchmarkEntity.cs | 24 +- .../TestData/Generate.cs | 34 +- .../MySqlDatabaseAdapter.cs | 42 +- .../MySqlEntityManipulator.cs | 48 +- .../MySqlTemporaryTableBuilder.cs | 26 +- .../OracleDatabaseAdapter.cs | 70 +- .../OracleEntityManipulator.cs | 50 +- .../OracleTemporaryTableBuilder.cs | 34 +- .../PostgreSqlDatabaseAdapter.cs | 64 +- .../PostgreSqlEntityManipulator.cs | 48 +- .../PostgreSqlTemporaryTableBuilder.cs | 24 +- .../SqlServerDatabaseAdapter.cs | 44 +- .../SqlServerEntityManipulator.cs | 48 +- .../SqlServerTemporaryTableBuilder.cs | 44 +- .../SqliteDatabaseAdapter.cs | 42 +- .../SqliteEntityManipulator.cs | 48 +- .../SqliteTemporaryTableBuilder.cs | 30 +- .../DbConnectionPlusConfiguration.cs | 2 +- .../Configuration/EntityPropertyBuilder.cs | 40 +- .../Configuration/EntityTypeBuilder.cs | 14 +- .../Configuration/IEntityPropertyBuilder.cs | 16 +- .../Configuration/IEntityTypeBuilder.cs | 4 +- .../Converters/EnumConverter.cs | 24 +- .../Converters/EnumSerializer.cs | 4 +- .../Converters/ValueConverter.cs | 542 +++++++------- .../DatabaseAdapters/Constants.cs | 4 +- .../DatabaseAdapters/IDatabaseAdapter.cs | 14 +- .../DatabaseAdapters/IEntityManipulator.cs | 24 +- .../ITemporaryTableBuilder.cs | 8 +- .../TemporaryTableDisposer.cs | 2 +- .../DbCommands/DbCommandBuilder.cs | 6 +- .../DbCommands/DbCommandDisposer.cs | 2 +- .../DbConnectionExtensions.Configuration.cs | 2 +- .../DbConnectionExtensions.DeleteEntities.cs | 4 +- .../DbConnectionExtensions.DeleteEntity.cs | 4 +- .../DbConnectionExtensions.ExecuteNonQuery.cs | 4 +- .../DbConnectionExtensions.ExecuteScalar.cs | 2 +- .../DbConnectionExtensions.Exists.cs | 8 +- .../DbConnectionExtensions.InsertEntities.cs | 4 +- .../DbConnectionExtensions.InsertEntity.cs | 4 +- .../DbConnectionExtensions.Parameter.cs | 8 +- .../DbConnectionExtensions.QueryFirstOfT.cs | 4 +- ...ectionExtensions.QueryFirstOrDefaultOfT.cs | 4 +- .../DbConnectionExtensions.QueryOfT.cs | 6 +- .../DbConnectionExtensions.QuerySingleOfT.cs | 4 +- ...ctionExtensions.QuerySingleOrDefaultOfT.cs | 4 +- .../DbConnectionExtensions.TemporaryTable.cs | 18 +- .../DbConnectionExtensions.UpdateEntities.cs | 4 +- .../DbConnectionExtensions.UpdateEntity.cs | 4 +- src/DbConnectionPlus/Dynamic/DataRow.cs | 42 +- src/DbConnectionPlus/Entities/EntityHelper.cs | 16 +- .../Entities/EntityPropertyMetadata.cs | 24 +- .../Entities/EntityTypeMetadata.cs | 4 +- .../DbUpdateConcurrencyException.cs | 8 +- .../Extensions/DbDataReaderExtensions.cs | 4 +- .../Extensions/Int32Extensions.cs | 4 +- .../Extensions/ObjectExtensions.cs | 46 +- .../Extensions/TypeExtensions.cs | 46 +- src/DbConnectionPlus/Helpers/NameHelper.cs | 14 +- .../Materializers/DataRowMaterializer.cs | 4 +- .../EntityMaterializerFactory.cs | 62 +- .../MaterializerFactoryHelper.cs | 80 +-- .../ValueTupleMaterializerFactory.cs | 50 +- .../CommandDisposingDataReaderDecorator.cs | 108 +-- .../Readers/EnumerableReader.cs | 214 +++--- .../Readers/EnumerableReaderOptions.cs | 6 +- .../SqlStatements/InterpolatedParameter.cs | 2 +- .../SqlStatements/InterpolatedSqlStatement.cs | 44 +- .../InterpolatedSqlStatementDebugView.cs | 2 +- .../InterpolatedTemporaryTable.cs | 2 +- src/DbConnectionPlus/SqlStatements/Literal.cs | 2 +- .../SqlStatements/Parameter.cs | 2 +- src/DbConnectionPlus/ThrowHelper.cs | 6 +- .../Assertions/EntityAssertions.cs | 22 +- .../EntityManipulator.DeleteEntitiesTests.cs | 28 +- .../EntityManipulator.DeleteEntityTests.cs | 28 +- .../EntityManipulator.InsertEntitiesTests.cs | 36 +- .../EntityManipulator.InsertEntityTests.cs | 36 +- .../EntityManipulator.UpdateEntitiesTests.cs | 52 +- .../EntityManipulator.UpdateEntityTests.cs | 52 +- .../Oracle/OracleDatabaseAdapterTests.cs | 2 +- .../TemporaryTableBuilderTests.cs | 78 +-- .../DbCommands/DbCommandBuilderTests.cs | 24 +- ...nnectionExtensions.ExecuteNonQueryTests.cs | 26 +- ...ConnectionExtensions.ExecuteReaderTests.cs | 24 +- ...ConnectionExtensions.ExecuteScalarTests.cs | 96 +-- .../DbConnectionExtensions.ExistsTests.cs | 26 +- .../DbConnectionExtensions.ParameterTests.cs | 14 +- ...ConnectionExtensions.QueryFirstOfTTests.cs | 206 +++--- ...nExtensions.QueryFirstOrDefaultOfTTests.cs | 210 +++--- ...tionExtensions.QueryFirstOrDefaultTests.cs | 30 +- .../DbConnectionExtensions.QueryFirstTests.cs | 26 +- .../DbConnectionExtensions.QueryOfTTests.cs | 206 +++--- ...onnectionExtensions.QuerySingleOfTTests.cs | 208 +++--- ...Extensions.QuerySingleOrDefaultOfTTests.cs | 212 +++--- ...ionExtensions.QuerySingleOrDefaultTests.cs | 32 +- ...DbConnectionExtensions.QuerySingleTests.cs | 28 +- .../DbConnectionExtensions.QueryTests.cs | 24 +- ...onnectionExtensions.TemporaryTableTests.cs | 28 +- .../IntegrationTestsBase.cs | 30 +- .../ITestDatabaseContainerFixture.cs | 2 +- .../Containers/MySqlContainerFixture.cs | 6 +- .../Containers/OracleContainerFixture.cs | 10 +- .../Containers/PostgreSqlContainerFixture.cs | 4 +- .../Containers/SqlServerContainerFixture.cs | 4 +- .../Containers/TestDatabaseContainer.cs | 4 +- .../Containers/TestDatabaseContainers.cs | 2 +- .../TestDatabaseDiagnosticMessageSink.cs | 2 +- .../TestDatabase/ITestDatabaseProvider.cs | 36 +- .../TestDatabase/MySqlTestDatabaseProvider.cs | 52 +- .../OracleTestDatabaseProvider.cs | 50 +- .../PostgreSqlTestDatabaseProvider.cs | 48 +- .../SQLiteTestDatabaseProvider.cs | 42 +- .../SqlServerTestDatabaseProvider.cs | 56 +- .../Assertions/DecoratorAssertions.cs | 6 +- .../DbConnectionPlusConfigurationTests.cs | 6 +- .../Converters/EnumConverterTests.cs | 78 +-- .../Converters/EnumSerializerTests.cs | 2 +- .../Converters/ValueConverterTests.cs | 662 +++++++++--------- .../MySql/MySqlDatabaseAdapterTests.cs | 48 +- .../MySql/MySqlTemporaryTableBuilderTests.cs | 12 +- .../Oracle/OracleDatabaseAdapterTests.cs | 86 +-- .../OracleTemporaryTableBuilderTests.cs | 16 +- .../PostgreSqlDatabaseAdapterTests.cs | 90 +-- .../PostgreSqlTemporaryTableBuilderTests.cs | 12 +- .../SqlServerDatabaseAdapterTests.cs | 50 +- .../SqlServerTemporaryTableBuilderTests.cs | 12 +- .../Sqlite/SqliteDatabaseAdapterTests.cs | 48 +- .../SqliteTemporaryTableBuilderTests.cs | 12 +- .../DbCommands/DbCommandBuilderTests.cs | 76 +- ...ConnectionExtensions.ExecuteScalarTests.cs | 8 +- .../DbConnectionExtensions.ParameterTests.cs | 8 +- ...ConnectionExtensions.QueryFirstOfTTests.cs | 2 +- ...nExtensions.QueryFirstOrDefaultOfTTests.cs | 2 +- ...tionExtensions.QueryFirstOrDefaultTests.cs | 2 +- .../DbConnectionExtensions.QueryFirstTests.cs | 2 +- .../DbConnectionExtensions.QueryOfTTests.cs | 2 +- ...onnectionExtensions.QuerySingleOfTTests.cs | 2 +- ...Extensions.QuerySingleOrDefaultOfTTests.cs | 2 +- ...ionExtensions.QuerySingleOrDefaultTests.cs | 2 +- ...DbConnectionExtensions.QuerySingleTests.cs | 2 +- .../DbConnectionExtensions.QueryTests.cs | 2 +- ...onnectionExtensions.TemporaryTableTests.cs | 18 +- .../Dynamic/DataRowTests.cs | 46 +- .../Entities/EntityHelperTests.cs | 36 +- .../Extensions/DbDataReaderExtensionsTests.cs | 4 +- .../Extensions/Int32ExtensionsTests.cs | 2 +- .../Extensions/ObjectExtensionsTests.cs | 38 +- .../Extensions/TypeExtensionsTests.cs | 106 +-- .../Helpers/NameHelperTests.cs | 6 +- .../Materializers/DataRowMaterializerTests.cs | 4 +- .../EntityMaterializerFactoryTests.cs | 148 ++-- .../MaterializerFactoryHelperTests.cs | 98 +-- .../ValueTupleMaterializerFactoryTests.cs | 194 ++--- .../Mocks/MockDbParameterCollection.cs | 34 +- ...ommandDisposingDataReaderDecoratorTests.cs | 14 +- .../Readers/EnumerableReaderOptionsTests.cs | 24 +- .../Readers/EnumerableReaderTests.cs | 58 +- .../InterpolatedSqlStatementTests.cs | 22 +- .../StatementMethodTestsBase.cs | 4 +- .../TestData/Entity.cs | 26 +- .../TestData/EntityWithDateTimeOffset.cs | 2 +- .../EntityWithDifferentCasingProperties.cs | 28 +- .../TestData/EntityWithEnumStoredAsInteger.cs | 2 +- .../TestData/EntityWithEnumStoredAsString.cs | 2 +- .../EntityWithMultipleIdentityProperties.cs | 4 +- .../TestData/EntityWithObjectProperty.cs | 2 +- .../TestData/EntityWithPrivateConstructor.cs | 26 +- .../TestData/EntityWithPublicConstructor.cs | 26 +- .../TestData/EntityWithoutKeyProperty.cs | 2 +- .../TestData/FakeConnectionA.cs | 10 +- .../TestData/FakeConnectionB.cs | 10 +- .../TestData/FakeConnectionC.cs | 10 +- .../TestData/Generate.cs | 46 +- .../TestData/Item.cs | 2 +- .../TestData/ItemWithConstructor.cs | 8 +- .../TestData/ItemWithPrivateConstructor.cs | 8 +- .../TestData/MappingTestEntity.cs | 8 +- .../TestData/MappingTestEntityAttributes.cs | 16 +- .../TestData/MappingTestEntityFluentApi.cs | 16 +- .../TestData/NotAValueTuple.cs | 8 +- .../TestData/TemporaryTableTestItem.cs | 20 +- ...raryTableTestItemWithNullableProperties.cs | 20 +- .../Trimming/ILLinkDescriptorsTests.cs | 8 +- .../UnitTestsBase.cs | 20 +- 207 files changed, 3528 insertions(+), 3528 deletions(-) diff --git a/benchmarks/DbConnectionPlus.Benchmarks/AotJobFilter.cs b/benchmarks/DbConnectionPlus.Benchmarks/AotJobFilter.cs index 68c0b82..62008b1 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/AotJobFilter.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/AotJobFilter.cs @@ -13,7 +13,7 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; // file for the measurements behind that. public class AotJobFilter : IFilter { - public Boolean Predicate(BenchmarkCase benchmarkCase) + public bool Predicate(BenchmarkCase benchmarkCase) { var isAotJob = benchmarkCase.Job.Id.Contains(BenchmarksConfig.AotJobId, StringComparison.Ordinal); var benchmarkName = benchmarkCase.Descriptor.WorkloadMethod.Name; @@ -31,7 +31,7 @@ public Boolean Predicate(BenchmarkCase benchmarkCase) // materializers with Reflection.Emit - so the only way to have it here is the Dapper.AOT build-time // generator, and that generator handles neither value tuples nor Dapper.Contrib, which is what the other // two categories compare against. - private static readonly HashSet AotJobBenchmarks = + private static readonly HashSet AotJobBenchmarks = [ nameof(Benchmarks.Query_Entities_Command), nameof(Benchmarks.Query_Entities_Dapper_Aot), @@ -43,5 +43,5 @@ public Boolean Predicate(BenchmarkCase benchmarkCase) ]; // Marks a benchmark as Native AOT only, so that it is kept out of the JIT job. - private const String AotOnlyBenchmarkSuffix = "_Aot"; + private const string AotOnlyBenchmarkSuffix = "_Aot"; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntities.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntities.cs index 2a83f7a..bfbf086 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntities.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntities.cs @@ -95,8 +95,8 @@ public void DeleteEntities_DbConnectionPlus() private List deleteEntities_batches = null!; - private const String DeleteEntities_Category = "DeleteEntities"; - private const Int32 DeleteEntities_EntitiesPerOperation = 250; + private const string DeleteEntities_Category = "DeleteEntities"; + private const int DeleteEntities_EntitiesPerOperation = 250; // Batches per invocation: one reported operation is one delete call over // DeleteEntities_EntitiesPerOperation entities. @@ -105,5 +105,5 @@ public void DeleteEntities_DbConnectionPlus() // DeleteEntity_OperationsPerInvoke for why that matters and for the measurement showing a rollback costs // what a commit costs. Twenty batches is 5 000 seeded rows, down from 75 000, and it amortizes the // transaction far past the point where it could affect the ratios. - private const Int32 DeleteEntities_OperationsPerInvoke = 20; + private const int DeleteEntities_OperationsPerInvoke = 20; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntity.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntity.cs index f3d6058..eb15846 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntity.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntity.cs @@ -83,7 +83,7 @@ public void DeleteEntity_DbConnectionPlus() transaction.Rollback(); } - private const String DeleteEntity_Category = "DeleteEntity"; + private const string DeleteEntity_Category = "DeleteEntity"; // Deletes per invocation, and also the number of rows seeded into the table. // @@ -101,5 +101,5 @@ public void DeleteEntity_DbConnectionPlus() // 0.5 us for the marginal delete. At one delete per invocation that fixed cost would be about two thirds // of the measurement - not a bias, since all three implementations pay it, but it would compress the // ratios this benchmark exists to show. Amortized over 1 000 deletes it is well under 1 %. - private const Int32 DeleteEntity_OperationsPerInvoke = 1000; + private const int DeleteEntity_OperationsPerInvoke = 1000; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteNonQuery.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteNonQuery.cs index 9dfba35..ce05cc6 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteNonQuery.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteNonQuery.cs @@ -57,5 +57,5 @@ public void ExecuteNonQuery_Dapper() => public void ExecuteNonQuery_DbConnectionPlus() => this.connection.ExecuteNonQuery($"DELETE FROM Entity WHERE Id = {Parameter(-1)}"); - private const String ExecuteNonQuery_Category = "ExecuteNonQuery"; + private const string ExecuteNonQuery_Category = "ExecuteNonQuery"; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteReader.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteReader.cs index 2d1db3c..dae7d43 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteReader.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteReader.cs @@ -81,5 +81,5 @@ public List ExecuteReader_DbConnectionPlus() return result; } - private const String ExecuteReader_Category = "ExecuteReader"; + private const string ExecuteReader_Category = "ExecuteReader"; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteScalar.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteScalar.cs index b56cc05..bf8e5bb 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteScalar.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteScalar.cs @@ -31,7 +31,7 @@ public void ExecuteScalar__Setup() => [Benchmark(Baseline = true)] [BenchmarkCategory(ExecuteScalar_Category)] - public String ExecuteScalar_Command() + public string ExecuteScalar_Command() { var entity = this.entitiesInDb[0]; @@ -45,16 +45,16 @@ public String ExecuteScalar_Command() command.Parameters.Add(idParameter); - return (String)command.ExecuteScalar()!; + return (string)command.ExecuteScalar()!; } [Benchmark(Baseline = false)] [BenchmarkCategory(ExecuteScalar_Category)] - public String ExecuteScalar_Dapper() + public string ExecuteScalar_Dapper() { var entity = this.entitiesInDb[0]; - return SqlMapper.ExecuteScalar( + return SqlMapper.ExecuteScalar( this.connection, "SELECT StringValue FROM Entity WHERE Id = @Id", new { entity.Id } @@ -63,14 +63,14 @@ public String ExecuteScalar_Dapper() [Benchmark(Baseline = false)] [BenchmarkCategory(ExecuteScalar_Category)] - public String ExecuteScalar_DbConnectionPlus() + public string ExecuteScalar_DbConnectionPlus() { var entity = this.entitiesInDb[0]; - return this.connection.ExecuteScalar( + return this.connection.ExecuteScalar( $"SELECT StringValue FROM Entity WHERE Id = {Parameter(entity.Id)}" ); } - private const String ExecuteScalar_Category = "ExecuteScalar"; + private const string ExecuteScalar_Category = "ExecuteScalar"; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Exists.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Exists.cs index 65e6233..90c850e 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Exists.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Exists.cs @@ -31,7 +31,7 @@ public void Exists__Setup() => [Benchmark(Baseline = true)] [BenchmarkCategory(Exists_Category)] - public Boolean Exists_Command() + public bool Exists_Command() { var entityId = this.entitiesInDb[0].Id; @@ -51,7 +51,7 @@ public Boolean Exists_Command() [Benchmark(Baseline = false)] [BenchmarkCategory(Exists_Category)] - public Boolean Exists_Dapper() + public bool Exists_Dapper() { var entityId = this.entitiesInDb[0].Id; @@ -66,12 +66,12 @@ public Boolean Exists_Dapper() [Benchmark(Baseline = false)] [BenchmarkCategory(Exists_Category)] - public Boolean Exists_DbConnectionPlus() + public bool Exists_DbConnectionPlus() { var entityId = this.entitiesInDb[0].Id; return this.connection.Exists($"SELECT 1 FROM Entity WHERE Id = {Parameter(entityId)}"); } - private const String Exists_Category = "Exists"; + private const string Exists_Category = "Exists"; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntities.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntities.cs index 839da7a..b382879 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntities.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntities.cs @@ -39,7 +39,7 @@ public void InsertEntities_Command() command.CommandText = InsertEntitySql; - var parameters = new Dictionary + var parameters = new Dictionary { { "Id", new("Id", null) }, { "BooleanValue", new("BooleanValue", null) }, @@ -100,12 +100,12 @@ private void AssignNextInsertEntitiesIds() private readonly List insertEntities_entitiesToInsert = Generate.Multiple(InsertEntities_EntitiesPerOperation); - private Int64 insertEntities_nextId; + private long insertEntities_nextId; - private const String InsertEntities_Category = "InsertEntities"; - private const Int32 InsertEntities_EntitiesPerOperation = 200; + private const string InsertEntities_Category = "InsertEntities"; + private const int InsertEntities_EntitiesPerOperation = 200; - private const String InsertEntitySql = """ + private const string InsertEntitySql = """ INSERT INTO Entity ( Id, diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntity.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntity.cs index bc229e2..b384e77 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntity.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntity.cs @@ -39,7 +39,7 @@ public void InsertEntity_Command() command.CommandText = InsertEntitySql; - var parameters = new Dictionary + var parameters = new Dictionary { { "Id", new("Id", null) }, { "BooleanValue", new("BooleanValue", null) }, @@ -89,7 +89,7 @@ private void AssignNextInsertEntityId() => // A fresh key per invocation, because Id is the primary key and the benchmarks insert the same entity over // and over into a table that starts out empty. - private Int64 insertEntity_nextId; + private long insertEntity_nextId; - private const String InsertEntity_Category = "InsertEntity"; + private const string InsertEntity_Category = "InsertEntity"; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Parameter.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Parameter.cs index 8daba2e..6eee0a5 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Parameter.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Parameter.cs @@ -31,7 +31,7 @@ public void Parameter__Setup() => [Benchmark(Baseline = true)] [BenchmarkCategory(Parameter_Category)] - public Int64 Parameter_Command() + public long Parameter_Command() { using var command = this.connection.CreateCommand(); @@ -48,13 +48,13 @@ public Int64 Parameter_Command() command.Parameters.Add(new("@P9", 9)); command.Parameters.Add(new("@P10", 10)); - return (Int64)command.ExecuteScalar()!; + return (long)command.ExecuteScalar()!; } [Benchmark(Baseline = false)] [BenchmarkCategory(Parameter_Category)] - public Int64 Parameter_Dapper() => - SqlMapper.ExecuteScalar( + public long Parameter_Dapper() => + SqlMapper.ExecuteScalar( this.connection, "SELECT @P1 + @P2 + @P3 + @P4 + @P5 + @P6 + @P7 + @P8 + @P9 + @P10", new { P1 = 1, P2 = 2, P3 = 3, P4 = 4, P5 = 5, P6 = 6, P7 = 7, P8 = 8, P9 = 9, P10 = 10 } @@ -62,13 +62,13 @@ public Int64 Parameter_Dapper() => [Benchmark(Baseline = false)] [BenchmarkCategory(Parameter_Category)] - public Int64 Parameter_DbConnectionPlus() => - this.connection.ExecuteScalar( + public long Parameter_DbConnectionPlus() => + this.connection.ExecuteScalar( $""" SELECT {Parameter(1)} + {Parameter(2)} + {Parameter(3)} + {Parameter(4)} + {Parameter(5)} + {Parameter(6)} + {Parameter(7)} + {Parameter(8)} + {Parameter(9)} + {Parameter(10)} """ ); - private const String Parameter_Category = "Parameter"; + private const string Parameter_Category = "Parameter"; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Dynamic.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Dynamic.cs index c3daac9..32f868f 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Dynamic.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Dynamic.cs @@ -41,25 +41,25 @@ public List Query_Dynamic_Command() while (dataReader.Read()) { - var charBuffer = new Char[1]; + var charBuffer = new char[1]; var ordinal = 0; - var dictionary = new Dictionary + var dictionary = new Dictionary { ["Id"] = dataReader.GetInt64(ordinal++), ["BooleanValue"] = dataReader.GetInt64(ordinal++) == 1, - ["BytesValue"] = (Byte[])dataReader.GetValue(ordinal++), + ["BytesValue"] = (byte[])dataReader.GetValue(ordinal++), ["ByteValue"] = dataReader.GetByte(ordinal++), ["CharValue"] = dataReader.GetChars(ordinal++, 0, charBuffer, 0, 1) == 1 ? charBuffer[0] : throw new InvalidOperationException(), ["DateTimeValue"] = DateTime.Parse(dataReader.GetString(ordinal++), CultureInfo.InvariantCulture), - ["DecimalValue"] = Decimal.Parse(dataReader.GetString(ordinal++), CultureInfo.InvariantCulture), + ["DecimalValue"] = decimal.Parse(dataReader.GetString(ordinal++), CultureInfo.InvariantCulture), ["DoubleValue"] = dataReader.GetDouble(ordinal++), ["EnumValue"] = Enum.Parse(dataReader.GetString(ordinal++)), - ["Int16Value"] = (Int16)dataReader.GetInt64(ordinal++), - ["Int32Value"] = (Int32)dataReader.GetInt64(ordinal++), + ["Int16Value"] = (short)dataReader.GetInt64(ordinal++), + ["Int32Value"] = (int)dataReader.GetInt64(ordinal++), ["Int64Value"] = dataReader.GetInt64(ordinal++), ["SingleValue"] = dataReader.GetFloat(ordinal++), ["StringValue"] = dataReader.GetString(ordinal) @@ -81,6 +81,6 @@ public List Query_Dynamic_Dapper() => public List Query_Dynamic_DbConnectionPlus() => [.. this.connection.Query("SELECT * FROM Entity")]; - private const String Query_Dynamic_Category = "Query_Dynamic"; - private const Int32 Query_Dynamic_EntitiesPerOperation = 100; + private const string Query_Dynamic_Category = "Query_Dynamic"; + private const int Query_Dynamic_EntitiesPerOperation = 100; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Entities.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Entities.cs index 82c92c2..9c90324 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Entities.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Entities.cs @@ -71,6 +71,6 @@ public List Query_Entities_Dapper_Aot() => public List Query_Entities_DbConnectionPlus() => [.. this.connection.Query("SELECT * FROM Entity")]; - private const String Query_Entities_Category = "Query_Entities"; - private const Int32 Query_Entities_EntitiesPerOperation = 100; + private const string Query_Entities_Category = "Query_Entities"; + private const int Query_Entities_EntitiesPerOperation = 100; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Scalars.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Scalars.cs index 864fc25..f754fc2 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Scalars.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Scalars.cs @@ -31,9 +31,9 @@ public void Query_Scalars__Setup() => [Benchmark(Baseline = true)] [BenchmarkCategory(Query_Scalars_Category)] - public List Query_Scalars_Command() + public List Query_Scalars_Command() { - var result = new List(); + var result = new List(); using var command = this.connection.CreateCommand(); @@ -51,14 +51,14 @@ public List Query_Scalars_Command() [Benchmark(Baseline = false)] [BenchmarkCategory(Query_Scalars_Category)] - public List Query_Scalars_Dapper() => - [.. SqlMapper.Query(this.connection, "SELECT Id FROM Entity")]; + public List Query_Scalars_Dapper() => + [.. SqlMapper.Query(this.connection, "SELECT Id FROM Entity")]; [Benchmark(Baseline = false)] [BenchmarkCategory(Query_Scalars_Category)] - public List Query_Scalars_DbConnectionPlus() => - [.. this.connection.Query("SELECT Id FROM Entity")]; + public List Query_Scalars_DbConnectionPlus() => + [.. this.connection.Query("SELECT Id FROM Entity")]; - private const String Query_Scalars_Category = "Query_Scalars"; - private const Int32 Query_Scalars_EntitiesPerOperation = 600; + private const string Query_Scalars_Category = "Query_Scalars"; + private const int Query_Scalars_EntitiesPerOperation = 600; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_ValueTuples.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_ValueTuples.cs index 6ca112e..d76598a 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_ValueTuples.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_ValueTuples.cs @@ -31,10 +31,10 @@ public void Query_ValueTuples__Setup() => [Benchmark(Baseline = true)] [BenchmarkCategory(Query_ValueTuples_Category)] - public List<(Int64 Id, DateTime DateTimeValue, TestEnum EnumValue, String StringValue)> + public List<(long Id, DateTime DateTimeValue, TestEnum EnumValue, string StringValue)> Query_ValueTuples_Command() { - var result = new List<(Int64 Id, DateTime DateTimeValue, TestEnum EnumValue, String StringValue)>(); + var result = new List<(long Id, DateTime DateTimeValue, TestEnum EnumValue, string StringValue)>(); using var command = this.connection.CreateCommand(); @@ -59,10 +59,10 @@ public void Query_ValueTuples__Setup() => [Benchmark(Baseline = false)] [BenchmarkCategory(Query_ValueTuples_Category)] - public List<(Int64 Id, DateTime DateTimeValue, TestEnum EnumValue, String StringValue)> + public List<(long Id, DateTime DateTimeValue, TestEnum EnumValue, string StringValue)> Query_ValueTuples_Dapper() => [.. SqlMapper - .Query<(Int64 Id, DateTime DateTimeValue, TestEnum EnumValue, String StringValue)>( + .Query<(long Id, DateTime DateTimeValue, TestEnum EnumValue, string StringValue)>( this.connection, "SELECT Id, DateTimeValue, EnumValue, StringValue FROM Entity" )]; @@ -75,13 +75,13 @@ [.. SqlMapper [Benchmark(Baseline = false)] [BenchmarkCategory(Query_ValueTuples_Category)] - public List<(Int64 Id, DateTime DateTimeValue, TestEnum EnumValue, String StringValue)> + public List<(long Id, DateTime DateTimeValue, TestEnum EnumValue, string StringValue)> Query_ValueTuples_DbConnectionPlus() => [.. this.connection - .Query<(Int64 Id, DateTime DateTimeValue, TestEnum EnumValue, String StringValue)>( + .Query<(long Id, DateTime DateTimeValue, TestEnum EnumValue, string StringValue)>( "SELECT Id, DateTimeValue, EnumValue, StringValue FROM Entity" )]; - private const String Query_ValueTuples_Category = "Query_ValueTuples"; - private const Int32 Query_ValueTuples_EntitiesPerOperation = 150; + private const string Query_ValueTuples_Category = "Query_ValueTuples"; + private const int Query_ValueTuples_EntitiesPerOperation = 150; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ComplexObjects.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ComplexObjects.cs index 762ab83..009b103 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ComplexObjects.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ComplexObjects.cs @@ -43,7 +43,7 @@ public List TemporaryTable_ComplexObjects_Command() insertCommand.CommandText = InsertIntoTempEntities; - var parameters = new Dictionary + var parameters = new Dictionary { { "Id", new("Id", null) }, { "BooleanValue", new("BooleanValue", null) }, @@ -129,7 +129,7 @@ public List TemporaryTable_ComplexObjects_DbConnectionPlus() => private readonly List temporaryTable_ComplexObjects_Entities = Generate.Multiple(TemporaryTable_ComplexObjects_EntitiesPerOperation); - private const String CreateTempEntitiesTableSql = """ + private const string CreateTempEntitiesTableSql = """ CREATE TEMP TABLE Entities ( Id INTEGER, BooleanValue INTEGER, @@ -148,7 +148,7 @@ StringValue TEXT ) """; - private const String InsertIntoTempEntities = """ + private const string InsertIntoTempEntities = """ INSERT INTO temp.Entities ( Id, BooleanValue, @@ -183,6 +183,6 @@ INSERT INTO temp.Entities ( ) """; - private const String TemporaryTable_ComplexObjects_Category = "TemporaryTable_ComplexObjects"; - private const Int32 TemporaryTable_ComplexObjects_EntitiesPerOperation = 250; + private const string TemporaryTable_ComplexObjects_Category = "TemporaryTable_ComplexObjects"; + private const int TemporaryTable_ComplexObjects_EntitiesPerOperation = 250; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ScalarValues.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ScalarValues.cs index 69f021a..5fd71fc 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ScalarValues.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ScalarValues.cs @@ -31,7 +31,7 @@ public void TemporaryTable_ScalarValues__Setup() => [Benchmark(Baseline = true)] [BenchmarkCategory(TemporaryTable_ScalarValues_Category)] - public List TemporaryTable_ScalarValues_Command() + public List TemporaryTable_ScalarValues_Command() { using var createTableCommand = this.connection.CreateCommand(); createTableCommand.CommandText = "CREATE TEMP TABLE \"Values\" (Value INTEGER)"; @@ -60,7 +60,7 @@ public List TemporaryTable_ScalarValues_Command() using var dataReader = selectCommand.ExecuteReader(); - var result = new List(); + var result = new List(); while (dataReader.Read()) { @@ -76,7 +76,7 @@ public List TemporaryTable_ScalarValues_Command() [Benchmark(Baseline = false)] [BenchmarkCategory(TemporaryTable_ScalarValues_Category)] - public List TemporaryTable_ScalarValues_Dapper() + public List TemporaryTable_ScalarValues_Dapper() { SqlMapper.Execute(this.connection, "CREATE TEMP TABLE \"Values\" (Value INTEGER)"); @@ -87,7 +87,7 @@ public List TemporaryTable_ScalarValues_Dapper() this.temporaryTable_ScalarValues_Values.Select(a => new { Value = a }) ); - var result = SqlMapper.Query(this.connection, "SELECT Value FROM temp.\"Values\"").ToList(); + var result = SqlMapper.Query(this.connection, "SELECT Value FROM temp.\"Values\"").ToList(); SqlMapper.Execute(this.connection, "DROP TABLE temp.\"Values\""); @@ -96,13 +96,13 @@ public List TemporaryTable_ScalarValues_Dapper() [Benchmark(Baseline = false)] [BenchmarkCategory(TemporaryTable_ScalarValues_Category)] - public List TemporaryTable_ScalarValues_DbConnectionPlus() => - [.. this.connection.Query($"SELECT Value FROM {TemporaryTable(this.temporaryTable_ScalarValues_Values)}")]; + public List TemporaryTable_ScalarValues_DbConnectionPlus() => + [.. this.connection.Query($"SELECT Value FROM {TemporaryTable(this.temporaryTable_ScalarValues_Values)}")]; - private readonly List temporaryTable_ScalarValues_Values = [.. Enumerable + private readonly List temporaryTable_ScalarValues_Values = [.. Enumerable .Range(0, TemporaryTable_ScalarValues_ValuesPerOperation) - .Select(a => (Int64)a)]; + .Select(a => (long)a)]; - private const String TemporaryTable_ScalarValues_Category = "TemporaryTable_ScalarValues"; - private const Int32 TemporaryTable_ScalarValues_ValuesPerOperation = 5000; + private const string TemporaryTable_ScalarValues_Category = "TemporaryTable_ScalarValues"; + private const int TemporaryTable_ScalarValues_ValuesPerOperation = 5000; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntities.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntities.cs index 5da4dee..4ca05a9 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntities.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntities.cs @@ -74,7 +74,7 @@ UPDATE Entity WHERE Id = @Id """; - var parameters = new Dictionary + var parameters = new Dictionary { { "Id", new("Id", null) }, { "BooleanValue", new("BooleanValue", null) }, @@ -113,9 +113,9 @@ public void UpdateEntities_DbConnectionPlus() => this.connection.UpdateEntities(this.UpdateEntities_GetNextModifiedEntities()); private List> updateEntities_ModifiedEntitiesPool = null!; - private Int32 updateEntities_ModifiedEntitiesPoolIndex; + private int updateEntities_ModifiedEntitiesPoolIndex; - private const String UpdateEntities_Category = "UpdateEntities"; - private const Int32 UpdateEntities_EntitiesPerOperation = 100; - private const Int32 UpdateEntities_UpdatedEntitiesPoolSize = 8; + private const string UpdateEntities_Category = "UpdateEntities"; + private const int UpdateEntities_EntitiesPerOperation = 100; + private const int UpdateEntities_UpdatedEntitiesPoolSize = 8; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntity.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntity.cs index 7ee2689..67a6162 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntity.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntity.cs @@ -78,7 +78,7 @@ UPDATE Entity WHERE Id = @Id """; - var parameters = new Dictionary + var parameters = new Dictionary { { "Id", new("Id", null) }, { "BooleanValue", new("BooleanValue", null) }, @@ -114,8 +114,8 @@ public void UpdateEntity_DbConnectionPlus() => this.connection.UpdateEntity(this.UpdateEntity_GetNextModifiedEntity()); private List updateEntity_ModifiedEntitiesPool = null!; - private Int32 updateEntity_ModifiedEntitiesPoolIndex; + private int updateEntity_ModifiedEntitiesPoolIndex; - private const String UpdateEntity_Category = "UpdateEntity"; - private const Int32 UpdateEntity_UpdatedEntityPoolSize = 64; + private const string UpdateEntity_Category = "UpdateEntity"; + private const int UpdateEntity_UpdatedEntityPoolSize = 64; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.cs index d778688..67aec8d 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.cs @@ -28,7 +28,7 @@ public Benchmarks() } } - private void SetupDatabase(Int32 numberOfEntities) + private void SetupDatabase(int numberOfEntities) { this.connection?.Dispose(); @@ -47,7 +47,7 @@ private void SetupDatabase(Int32 numberOfEntities) transaction.Commit(); } - private static void PopulateEntityParameters(BenchmarkEntity entity, Dictionary parameters) + private static void PopulateEntityParameters(BenchmarkEntity entity, Dictionary parameters) { parameters["Id"].Value = entity.Id; parameters["BooleanValue"].Value = entity.BooleanValue ? 1 : 0; @@ -67,7 +67,7 @@ private static void PopulateEntityParameters(BenchmarkEntity entity, Dictionary< private static BenchmarkEntity ReadEntity(IDataReader dataReader) { - var charBuffer = new Char[1]; + var charBuffer = new char[1]; var ordinal = 0; @@ -75,15 +75,15 @@ private static BenchmarkEntity ReadEntity(IDataReader dataReader) { Id = dataReader.GetInt64(ordinal++), BooleanValue = dataReader.GetInt64(ordinal++) == 1, - BytesValue = (Byte[])dataReader.GetValue(ordinal++), + BytesValue = (byte[])dataReader.GetValue(ordinal++), ByteValue = dataReader.GetByte(ordinal++), CharValue = dataReader.GetChars(ordinal++, 0, charBuffer, 0, 1) == 1 ? charBuffer[0] : throw new InvalidOperationException(), DateTimeValue = DateTime.Parse(dataReader.GetString(ordinal++), CultureInfo.InvariantCulture), - DecimalValue = Decimal.Parse(dataReader.GetString(ordinal++), CultureInfo.InvariantCulture), + DecimalValue = decimal.Parse(dataReader.GetString(ordinal++), CultureInfo.InvariantCulture), DoubleValue = dataReader.GetDouble(ordinal++), EnumValue = Enum.Parse(dataReader.GetString(ordinal++)), - Int16Value = (Int16)dataReader.GetInt64(ordinal++), - Int32Value = (Int32)dataReader.GetInt64(ordinal++), + Int16Value = (short)dataReader.GetInt64(ordinal++), + Int32Value = (int)dataReader.GetInt64(ordinal++), Int64Value = dataReader.GetInt64(ordinal++), SingleValue = dataReader.GetFloat(ordinal++), StringValue = dataReader.GetString(ordinal) @@ -99,7 +99,7 @@ private static BenchmarkEntity ReadEntity(IDataReader dataReader) * update, exists and scalar benchmarks and made their results a function of the seeded row count rather than of * the code under test. */ - private const String CreateEntityTableSql = + private const string CreateEntityTableSql = """ CREATE TABLE Entity ( diff --git a/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksConfig.cs b/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksConfig.cs index ab808a8..c001ad2 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksConfig.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksConfig.cs @@ -37,7 +37,7 @@ public BenchmarksConfig() } // The settings both jobs share, so that the only difference between them is the toolchain. - private static Job CreateJob(String id) => + private static Job CreateJob(string id) => Job.Default .WithId(id) // The default adaptive warmup runs ~9 iterations, but every iteration already executes tens of @@ -54,6 +54,6 @@ private static Job CreateJob(String id) => .WithGcServer(true); // The Job column of the summary shows these. - public const String JitJobId = "JIT"; - public const String AotJobId = "AOT"; + public const string JitJobId = "JIT"; + public const string AotJobId = "AOT"; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksOrderer.cs b/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksOrderer.cs index 9431d8d..8421e59 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksOrderer.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksOrderer.cs @@ -17,7 +17,7 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; // against AOT comparison is read from the Mean column of the two rows for the same method. public class BenchmarksOrderer : IOrderer { - public Boolean SeparateLogicalGroups => true; + public bool SeparateLogicalGroups => true; public IEnumerable GetExecutionOrder( ImmutableArray benchmarksCase, @@ -25,17 +25,17 @@ public IEnumerable GetExecutionOrder( ) => Sort(benchmarksCase); - public String? GetHighlightGroupKey(BenchmarkCase benchmarkCase) => + public string? GetHighlightGroupKey(BenchmarkCase benchmarkCase) => GetLogicalGroupKey(benchmarkCase); - public String? GetLogicalGroupKey( + public string? GetLogicalGroupKey( ImmutableArray allBenchmarksCases, BenchmarkCase benchmarkCase ) => GetLogicalGroupKey(benchmarkCase); - public IEnumerable> GetLogicalGroupOrder( - IEnumerable> logicalGroups, + public IEnumerable> GetLogicalGroupOrder( + IEnumerable> logicalGroups, IEnumerable? order = null ) => logicalGroups @@ -55,10 +55,10 @@ private static IEnumerable Sort(ImmutableArray ben .ThenByDescending(a => a.Descriptor.Baseline) .ThenBy(a => a.Descriptor.WorkloadMethod.Name, StringComparer.Ordinal); - private static String GetLogicalGroupKey(BenchmarkCase benchmarkCase) => + private static string GetLogicalGroupKey(BenchmarkCase benchmarkCase) => $"{benchmarkCase.Descriptor.Categories.FirstOrDefault()}-{benchmarkCase.Job.Id}"; // Ranked rather than sorted by name, so that JIT is reported before AOT instead of alphabetically. - private static Int32 GetJobRank(BenchmarkCase benchmarkCase) => + private static int GetJobRank(BenchmarkCase benchmarkCase) => benchmarkCase.Job.Id.Contains(BenchmarksConfig.JitJobId, StringComparison.Ordinal) ? 0 : 1; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Program.cs b/benchmarks/DbConnectionPlus.Benchmarks/Program.cs index 3d2df03..2591a77 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Program.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Program.cs @@ -4,7 +4,7 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public static class Program { - public static void Main(String[] args) => + public static void Main(string[] args) => BenchmarkSwitcher .FromAssembly(typeof(Program).Assembly) .Run(args); diff --git a/benchmarks/DbConnectionPlus.Benchmarks/TestData/BenchmarkEntity.cs b/benchmarks/DbConnectionPlus.Benchmarks/TestData/BenchmarkEntity.cs index 7315d19..3d684d9 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/TestData/BenchmarkEntity.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/TestData/BenchmarkEntity.cs @@ -9,22 +9,22 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks.TestData; [System.ComponentModel.DataAnnotations.Schema.Table("Entity")] public record BenchmarkEntity { - public Boolean BooleanValue { get; set; } - public Byte[] BytesValue { get; set; } = null!; - public Byte ByteValue { get; set; } - public Char CharValue { get; set; } + public bool BooleanValue { get; set; } + public byte[] BytesValue { get; set; } = null!; + public byte ByteValue { get; set; } + public char CharValue { get; set; } public DateTime DateTimeValue { get; set; } - public Decimal DecimalValue { get; set; } - public Double DoubleValue { get; set; } + public decimal DecimalValue { get; set; } + public double DoubleValue { get; set; } public TestEnum EnumValue { get; set; } [System.ComponentModel.DataAnnotations.Key] - public Int64 Id { get; set; } + public long Id { get; set; } - public Int16 Int16Value { get; set; } - public Int32 Int32Value { get; set; } - public Int64 Int64Value { get; set; } + public short Int16Value { get; set; } + public int Int32Value { get; set; } + public long Int64Value { get; set; } - public Single SingleValue { get; set; } - public String StringValue { get; set; } = null!; + public float SingleValue { get; set; } + public string StringValue { get; set; } = null!; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/TestData/Generate.cs b/benchmarks/DbConnectionPlus.Benchmarks/TestData/Generate.cs index a6812b6..1439afb 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/TestData/Generate.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/TestData/Generate.cs @@ -25,7 +25,7 @@ public static class Generate public static BenchmarkEntity Single() => Create(NextId()); - public static List Multiple(Int32 numberOfEntities) => + public static List Multiple(int numberOfEntities) => [.. Enumerable.Range(0, numberOfEntities).Select(_ => Single())]; public static BenchmarkEntity UpdateFor(BenchmarkEntity entity) @@ -45,7 +45,7 @@ public static BenchmarkEntity UpdateFor(BenchmarkEntity entity) public static List UpdatesFor(List entities) => [.. entities.Select(UpdateFor)]; - private static BenchmarkEntity Create(Int64 id) + private static BenchmarkEntity Create(long id) { lock (syncRoot) { @@ -54,54 +54,54 @@ private static BenchmarkEntity Create(Int64 id) Id = id, BooleanValue = random.Next(2) == 1, BytesValue = NextBytes(random.Next(1, 10)), - ByteValue = (Byte)random.Next(0, 256), + ByteValue = (byte)random.Next(0, 256), CharValue = characters[random.Next(0, characters.Length)], // Seconds precision, and a fixed base date so that the values do not depend on when the benchmarks // are run. The span covers roughly six years. DateTimeValue = dateTimeBase.AddSeconds(random.Next(0, 200_000_000)), - DecimalValue = Math.Round((Decimal)(random.NextDouble() * 999.0), 10), + DecimalValue = Math.Round((decimal)(random.NextDouble() * 999.0), 10), DoubleValue = Math.Round(random.NextDouble() * 999.0, 3), EnumValue = (TestEnum)random.Next(1, 6), - Int16Value = (Int16)random.Next(Int16.MinValue, Int16.MaxValue + 1), - Int32Value = random.Next(Int32.MinValue, Int32.MaxValue), + Int16Value = (short)random.Next(short.MinValue, short.MaxValue + 1), + Int32Value = random.Next(int.MinValue, int.MaxValue), Int64Value = random.NextInt64(), - SingleValue = (Single)Math.Round(random.NextDouble() * 999.0, 3), + SingleValue = (float)Math.Round(random.NextDouble() * 999.0, 3), StringValue = NextSentence() }; } } - private static Int64 NextId() => + private static long NextId() => Interlocked.Increment(ref nextId); - private static Byte[] NextBytes(Int32 count) + private static byte[] NextBytes(int count) { - var bytes = new Byte[count]; + var bytes = new byte[count]; random.NextBytes(bytes); return bytes; } - private static String NextSentence() + private static string NextSentence() { var wordCount = random.Next(4, 9); - var sentence = new String[wordCount]; + var sentence = new string[wordCount]; for (var i = 0; i < wordCount; i++) { sentence[i] = words[random.Next(0, words.Length)]; } - sentence[0] = String.Concat( + sentence[0] = string.Concat( sentence[0][..1].ToUpper(CultureInfo.InvariantCulture), sentence[0].AsSpan(1) ); - return String.Join(' ', sentence) + '.'; + return string.Join(' ', sentence) + '.'; } - private static Int64 nextId; + private static long nextId; // Seeded, so that every process generates the same entities. private static readonly Random random = new(20260813); @@ -110,9 +110,9 @@ private static String NextSentence() // returning zeroes once it is not, which would be invisible in a benchmark result. private static readonly Lock syncRoot = new(); - private static readonly Char[] characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray(); + private static readonly char[] characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray(); - private static readonly String[] words = + private static readonly string[] words = [ "lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing", "elit", "sed", "do", "eiusmod", "tempor", "incididunt", "ut", "labore", "et", "dolore", "magna", "aliqua", "enim", "ad", "minim", "veniam", diff --git a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlDatabaseAdapter.cs b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlDatabaseAdapter.cs index 16d314b..2d2ffb1 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlDatabaseAdapter.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlDatabaseAdapter.cs @@ -27,7 +27,7 @@ public MySqlDatabaseAdapter() this.temporaryTableBuilder; /// - public void BindParameterValue(DbParameter parameter, Object? value) + public void BindParameterValue(DbParameter parameter, object? value) { ArgumentNullException.ThrowIfNull(parameter); @@ -59,7 +59,7 @@ public void BindParameterValue(DbParameter parameter, Object? value) ); break; - case Byte[]: + case byte[]: parameter.DbType = DbType.Binary; parameter.Value = value; break; @@ -71,11 +71,11 @@ public void BindParameterValue(DbParameter parameter, Object? value) } /// - public String FormatParameterName(String parameterName) => + public string FormatParameterName(string parameterName) => "@" + parameterName; /// - public String GetDataType(Type type, EnumSerializationMode enumSerializationMode) + public string GetDataType(Type type, EnumSerializationMode enumSerializationMode) { ArgumentNullException.ThrowIfNull(type); @@ -92,7 +92,7 @@ public String GetDataType(Type type, EnumSerializationMode enumSerializationMode EnumSerializationMode.Integers => "INT", - _ => ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode) + _ => ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode) }; } @@ -109,19 +109,19 @@ public String GetDataType(Type type, EnumSerializationMode enumSerializationMode } /// - public String QuoteIdentifier(String identifier) => + public string QuoteIdentifier(string identifier) => "`" + identifier + "`"; /// - public String QuoteTemporaryTableName(String tableName, DbConnection connection) => + public string QuoteTemporaryTableName(string tableName, DbConnection connection) => "`" + tableName + "`"; /// - public Boolean SupportsTemporaryTables(DbConnection connection) => + public bool SupportsTemporaryTables(DbConnection connection) => true; /// - public Boolean WasSqlStatementCancelledByCancellationToken(Exception exception, CancellationToken cancellationToken) + public bool WasSqlStatementCancelledByCancellationToken(Exception exception, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(exception); @@ -132,22 +132,22 @@ public Boolean WasSqlStatementCancelledByCancellationToken(Exception exception, private readonly MySqlEntityManipulator entityManipulator; private readonly MySqlTemporaryTableBuilder temporaryTableBuilder; - private static readonly Dictionary typeToMySqlDataType = new() + private static readonly Dictionary typeToMySqlDataType = new() { - { typeof(Boolean), "TINYINT(1)" }, - { typeof(Byte), "TINYINT UNSIGNED" }, - { typeof(Byte[]), "BLOB" }, - { typeof(Char), "CHAR(1)" }, + { typeof(bool), "TINYINT(1)" }, + { typeof(byte), "TINYINT UNSIGNED" }, + { typeof(byte[]), "BLOB" }, + { typeof(char), "CHAR(1)" }, { typeof(DateOnly), "DATE" }, { typeof(DateTime), "DATETIME" }, - { typeof(Decimal), "DECIMAL(65,30)" }, - { typeof(Double), "DOUBLE" }, + { typeof(decimal), "DECIMAL(65,30)" }, + { typeof(double), "DOUBLE" }, { typeof(Guid), "CHAR(36)" }, - { typeof(Int16), "SMALLINT" }, - { typeof(Int32), "INT" }, - { typeof(Int64), "BIGINT" }, - { typeof(Single), "FLOAT" }, - { typeof(String), "TEXT" }, + { typeof(short), "SMALLINT" }, + { typeof(int), "INT" }, + { typeof(long), "BIGINT" }, + { typeof(float), "FLOAT" }, + { typeof(string), "TEXT" }, { typeof(TimeOnly), "TIME" }, { typeof(TimeSpan), "TIME" } }; diff --git a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlEntityManipulator.cs index 32f1126..bc1d03c 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlEntityManipulator.cs @@ -23,7 +23,7 @@ public MySqlEntityManipulator(MySqlDatabaseAdapter databaseAdapter) => #pragma warning restore IDE0290 // Use primary constructor /// - public Int32 DeleteEntities< + public int DeleteEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -86,7 +86,7 @@ CancellationToken cancellationToken } /// - public async Task DeleteEntitiesAsync< + public async Task DeleteEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -150,7 +150,7 @@ CancellationToken cancellationToken } /// - public Int32 DeleteEntity< + public int DeleteEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -201,7 +201,7 @@ CancellationToken cancellationToken } /// - public async Task DeleteEntityAsync< + public async Task DeleteEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -252,7 +252,7 @@ CancellationToken cancellationToken } /// - public Int32 InsertEntities< + public int InsertEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -309,7 +309,7 @@ CancellationToken cancellationToken } /// - public async Task InsertEntitiesAsync< + public async Task InsertEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -375,7 +375,7 @@ await UpdateDatabaseGeneratedPropertiesAsync( } /// - public Int32 InsertEntity< + public int InsertEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -421,7 +421,7 @@ CancellationToken cancellationToken } /// - public async Task InsertEntityAsync< + public async Task InsertEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -471,7 +471,7 @@ await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, } /// - public Int32 UpdateEntities< + public int UpdateEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -543,7 +543,7 @@ CancellationToken cancellationToken } /// - public async Task UpdateEntitiesAsync< + public async Task UpdateEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -623,7 +623,7 @@ await UpdateDatabaseGeneratedPropertiesAsync( } /// - public Int32 UpdateEntity< + public int UpdateEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -683,7 +683,7 @@ CancellationToken cancellationToken } /// - public async Task UpdateEntityAsync< + public async Task UpdateEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -864,7 +864,7 @@ EntityTypeMetadata entityTypeMetadata /// /// The metadata for the entity type to delete. /// The SQL code to delete an entity of the specified type. - private String GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => + private string GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => this.entityDeleteSqlCodePerEntityType.GetOrAdd( entityTypeMetadata.EntityType, _ => @@ -874,7 +874,7 @@ private String GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => ThrowHelper.ThrowEntityTypeHasNoKeyPropertyException(entityTypeMetadata.EntityType); } - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.AppendLine("DELETE FROM"); @@ -918,12 +918,12 @@ private String GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => /// /// The metadata for the entity type to insert. /// The SQL code to insert an entity of the specified type. - private String GetInsertEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => + private string GetInsertEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => this.entityInsertSqlCodePerEntityType.GetOrAdd( entityTypeMetadata.EntityType, _ => { - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.Append("INSERT INTO `"); sqlBuilder.Append(entityTypeMetadata.TableName); @@ -1049,7 +1049,7 @@ private String GetInsertEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => /// /// The metadata for the entity type to update. /// The SQL code to update an entity of the specified type. - private String GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => + private string GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => this.entityUpdateSqlCodePerEntityType.GetOrAdd( entityTypeMetadata.EntityType, _ => @@ -1059,7 +1059,7 @@ private String GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => ThrowHelper.ThrowEntityTypeHasNoKeyPropertyException(entityTypeMetadata.EntityType); } - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.AppendLine("UPDATE"); @@ -1194,7 +1194,7 @@ .. entityTypeMetadata.ConcurrencyTokenProperties private void PopulateParametersFromEntityProperties( EntityTypeMetadata entityTypeMetadata, List parameters, - Object entity + object entity ) { ArgumentNullException.ThrowIfNull(parameters); @@ -1218,7 +1218,7 @@ Object entity private static void UpdateDatabaseGeneratedProperties( EntityTypeMetadata entityTypeMetadata, DbDataReader reader, - Object entity, + object entity, CancellationToken cancellationToken ) { @@ -1256,7 +1256,7 @@ CancellationToken cancellationToken private static async Task UpdateDatabaseGeneratedPropertiesAsync( EntityTypeMetadata entityTypeMetadata, DbDataReader reader, - Object entity, + object entity, CancellationToken cancellationToken ) { @@ -1284,7 +1284,7 @@ await reader.ReadAsync(cancellationToken).ConfigureAwait(false) } private readonly MySqlDatabaseAdapter databaseAdapter; - private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); - private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); - private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); } diff --git a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlTemporaryTableBuilder.cs b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlTemporaryTableBuilder.cs index 0700f00..f7070e3 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlTemporaryTableBuilder.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlTemporaryTableBuilder.cs @@ -34,7 +34,7 @@ public MySqlTemporaryTableBuilder(MySqlDatabaseAdapter databaseAdapter) public TemporaryTableDisposer BuildTemporaryTable( DbConnection connection, DbTransaction? transaction, - String name, + string name, IEnumerable values, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, @@ -134,7 +134,7 @@ public TemporaryTableDisposer BuildTemporaryTable( public async Task BuildTemporaryTableAsync( DbConnection connection, DbTransaction? transaction, - String name, + string name, IEnumerable values, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, @@ -249,14 +249,14 @@ public async Task BuildTemporaryTableAsync( /// The type of objects with which to populate the table. /// The mode to use to serialize values. /// The built SQL code. - private String BuildCreateMultiColumnTemporaryTableSqlCode( - String tableName, + private string BuildCreateMultiColumnTemporaryTableSqlCode( + string tableName, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type objectsType, EnumSerializationMode enumSerializationMode ) { - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.Append("CREATE TEMPORARY TABLE `"); sqlBuilder.Append(tableName); @@ -300,14 +300,14 @@ EnumSerializationMode enumSerializationMode /// The type of values with which the table will be populated. /// The mode to use to serialize values. /// The built SQL code. - private String BuildCreateSingleColumnTemporaryTableSqlCode( - String tableName, + private string BuildCreateSingleColumnTemporaryTableSqlCode( + string tableName, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, EnumSerializationMode enumSerializationMode ) { - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[100]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[100]); sqlBuilder.Append("CREATE TEMPORARY TABLE `"); sqlBuilder.Append(tableName); @@ -340,7 +340,7 @@ private static EnumerableReader CreateValuesDataReader( { if (valuesType.IsEnumOrNullableEnumType()) { - var enumValues = new List(); + var enumValues = new List(); foreach (var value in values) { @@ -368,14 +368,14 @@ private static EnumerableReader CreateValuesDataReader( case EnumSerializationMode.Integers: return new EnumerableReader( enumValues, - typeof(Int32?), + typeof(int?), Constants.SingleColumnTemporaryTableColumnName ); case EnumSerializationMode.Strings: return new EnumerableReader( enumValues, - typeof(String), + typeof(string), Constants.SingleColumnTemporaryTableColumnName ); @@ -402,7 +402,7 @@ [.. EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a /// The name of the table to drop. /// The connection to use to drop the table. /// The transaction within to drop the table. - private static void DropTemporaryTable(String name, MySqlConnection connection, MySqlTransaction? transaction) + private static void DropTemporaryTable(string name, MySqlConnection connection, MySqlTransaction? transaction) { using var command = connection.CreateCommand(); @@ -422,7 +422,7 @@ private static void DropTemporaryTable(String name, MySqlConnection connection, /// The transaction within to drop the table. /// A task representing the asynchronous operation. private static async ValueTask DropTemporaryTableAsync( - String name, + string name, MySqlConnection connection, MySqlTransaction? transaction ) diff --git a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleDatabaseAdapter.cs b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleDatabaseAdapter.cs index a1edfbc..0e0783e 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleDatabaseAdapter.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleDatabaseAdapter.cs @@ -38,7 +38,7 @@ public ITemporaryTableBuilder TemporaryTableBuilder } /// - public void BindParameterValue(DbParameter parameter, Object? value) + public void BindParameterValue(DbParameter parameter, object? value) { ArgumentNullException.ThrowIfNull(parameter); @@ -75,7 +75,7 @@ public void BindParameterValue(DbParameter parameter, Object? value) ); break; - case Byte[]: + case byte[]: parameter.DbType = DbType.Binary; parameter.Value = value; break; @@ -98,11 +98,11 @@ public void BindParameterValue(DbParameter parameter, Object? value) } /// - public String FormatParameterName(String parameterName) => + public string FormatParameterName(string parameterName) => ":\"" + parameterName + "\""; /// - public String GetDataType(Type type, EnumSerializationMode enumSerializationMode) + public string GetDataType(Type type, EnumSerializationMode enumSerializationMode) { ArgumentNullException.ThrowIfNull(type); @@ -120,7 +120,7 @@ public String GetDataType(Type type, EnumSerializationMode enumSerializationMode "NUMBER(10)", _ => - ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode) + ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode) }; } @@ -198,13 +198,13 @@ public DbType GetDbType(Type type, EnumSerializationMode enumSerializationMode) } /// - public String QuoteIdentifier(String identifier) => + public string QuoteIdentifier(string identifier) => "\"" + identifier + "\""; /// - public String QuoteTemporaryTableName(String tableName, DbConnection connection) + public string QuoteTemporaryTableName(string tableName, DbConnection connection) { - var prefix = connection.ExecuteScalar( + var prefix = connection.ExecuteScalar( "SELECT VALUE FROM v$parameter WHERE NAME = 'private_temp_table_prefix'" ); @@ -212,7 +212,7 @@ public String QuoteTemporaryTableName(String tableName, DbConnection connection) } /// - public Boolean SupportsTemporaryTables(DbConnection connection) + public bool SupportsTemporaryTables(DbConnection connection) { ArgumentNullException.ThrowIfNull(connection); @@ -224,7 +224,7 @@ public Boolean SupportsTemporaryTables(DbConnection connection) } /// - public Boolean WasSqlStatementCancelledByCancellationToken( + public bool WasSqlStatementCancelledByCancellationToken( Exception exception, CancellationToken cancellationToken ) @@ -278,7 +278,7 @@ CancellationToken cancellationToken /// /// If set to , attempting to use the temporary tables feature will throw an exception. /// - public static Boolean AllowTemporaryTables { get; set; } + public static bool AllowTemporaryTables { get; set; } /// /// Throws an indicating that the temporary tables feature of @@ -294,47 +294,47 @@ internal static void ThrowTemporaryTablesFeatureIsDisabledException() => ); private readonly OracleEntityManipulator entityManipulator; - private readonly ConcurrentDictionary supportsTemporaryTablesPerConnectionString = []; + private readonly ConcurrentDictionary supportsTemporaryTablesPerConnectionString = []; private readonly OracleTemporaryTableBuilder temporaryTableBuilder; private static readonly Dictionary typeToDbType = new() { - { typeof(Boolean), DbType.Boolean }, - { typeof(Byte), DbType.Byte }, - { typeof(Byte[]), DbType.Binary }, - { typeof(Char), DbType.StringFixedLength }, + { typeof(bool), DbType.Boolean }, + { typeof(byte), DbType.Byte }, + { typeof(byte[]), DbType.Binary }, + { typeof(char), DbType.StringFixedLength }, { typeof(DateOnly), DbType.Date }, { typeof(DateTime), DbType.DateTime }, { typeof(DateTimeOffset), DbType.DateTimeOffset }, - { typeof(Decimal), DbType.Decimal }, - { typeof(Double), DbType.Double }, + { typeof(decimal), DbType.Decimal }, + { typeof(double), DbType.Double }, { typeof(Guid), DbType.Guid }, - { typeof(Int16), DbType.Int16 }, - { typeof(Int32), DbType.Int32 }, - { typeof(Int64), DbType.Int64 }, - { typeof(Single), DbType.Single }, - { typeof(String), DbType.String }, + { typeof(short), DbType.Int16 }, + { typeof(int), DbType.Int32 }, + { typeof(long), DbType.Int64 }, + { typeof(float), DbType.Single }, + { typeof(string), DbType.String }, { typeof(TimeOnly), DbType.Time }, { typeof(TimeSpan), DbType.Time } }; - private static readonly Dictionary typeToOracleDataType = new() + private static readonly Dictionary typeToOracleDataType = new() { - { typeof(Boolean), "NUMBER(1)" }, - { typeof(Byte), "NUMBER(3)" }, - { typeof(Byte[]), "RAW(2000)" }, - { typeof(Char), "CHAR(1)" }, + { typeof(bool), "NUMBER(1)" }, + { typeof(byte), "NUMBER(3)" }, + { typeof(byte[]), "RAW(2000)" }, + { typeof(char), "CHAR(1)" }, { typeof(DateOnly), "DATE" }, { typeof(DateTime), "TIMESTAMP" }, { typeof(DateTimeOffset), "TIMESTAMP WITH TIME ZONE" }, - { typeof(Decimal), "NUMBER(28,10)" }, - { typeof(Double), "BINARY_DOUBLE" }, + { typeof(decimal), "NUMBER(28,10)" }, + { typeof(double), "BINARY_DOUBLE" }, { typeof(Guid), "RAW(16)" }, - { typeof(Int16), "NUMBER(5)" }, - { typeof(Int32), "NUMBER(10)" }, - { typeof(Int64), "NUMBER(19)" }, - { typeof(Single), "BINARY_FLOAT" }, - { typeof(String), "NVARCHAR2(2000)" }, + { typeof(short), "NUMBER(5)" }, + { typeof(int), "NUMBER(10)" }, + { typeof(long), "NUMBER(19)" }, + { typeof(float), "BINARY_FLOAT" }, + { typeof(string), "NVARCHAR2(2000)" }, { typeof(TimeOnly), "INTERVAL DAY TO SECOND" }, { typeof(TimeSpan), "INTERVAL DAY TO SECOND" } }; diff --git a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleEntityManipulator.cs index 3210d8f..e64d83c 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleEntityManipulator.cs @@ -21,7 +21,7 @@ public OracleEntityManipulator(OracleDatabaseAdapter databaseAdapter) => this.databaseAdapter = databaseAdapter; /// - public Int32 DeleteEntities< + public int DeleteEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -84,7 +84,7 @@ CancellationToken cancellationToken } /// - public async Task DeleteEntitiesAsync< + public async Task DeleteEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -148,7 +148,7 @@ CancellationToken cancellationToken } /// - public Int32 DeleteEntity< + public int DeleteEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -199,7 +199,7 @@ CancellationToken cancellationToken } /// - public async Task DeleteEntityAsync< + public async Task DeleteEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -250,7 +250,7 @@ CancellationToken cancellationToken } /// - public Int32 InsertEntities< + public int InsertEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -308,7 +308,7 @@ CancellationToken cancellationToken } /// - public async Task InsertEntitiesAsync< + public async Task InsertEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -367,7 +367,7 @@ CancellationToken cancellationToken } /// - public Int32 InsertEntity< + public int InsertEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -415,7 +415,7 @@ CancellationToken cancellationToken } /// - public async Task InsertEntityAsync< + public async Task InsertEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -463,7 +463,7 @@ CancellationToken cancellationToken } /// - public Int32 UpdateEntities< + public int UpdateEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -532,7 +532,7 @@ CancellationToken cancellationToken } /// - public async Task UpdateEntitiesAsync< + public async Task UpdateEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -602,7 +602,7 @@ CancellationToken cancellationToken } /// - public Int32 UpdateEntity< + public int UpdateEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -659,7 +659,7 @@ CancellationToken cancellationToken } /// - public async Task UpdateEntityAsync< + public async Task UpdateEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -801,7 +801,7 @@ EntityTypeMetadata entityTypeMetadata parameter.Direction = ParameterDirection.Output; - if (property.PropertyType == typeof(Byte[])) + if (property.PropertyType == typeof(byte[])) { // Use max size for byte arrays to actually retrieve the full value: parameter.Size = 32767; @@ -864,7 +864,7 @@ EntityTypeMetadata entityTypeMetadata parameter.Direction = ParameterDirection.Output; - if (property.PropertyType == typeof(Byte[])) + if (property.PropertyType == typeof(byte[])) { // Use max size for byte arrays to actually retrieve the full value: parameter.Size = 32767; @@ -882,7 +882,7 @@ EntityTypeMetadata entityTypeMetadata /// /// The metadata for the entity type to delete. /// The SQL code to delete an entity of the specified type. - private String GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => + private string GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => this.entityDeleteSqlCodePerEntityType.GetOrAdd( entityTypeMetadata.EntityType, _ => @@ -892,7 +892,7 @@ private String GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => ThrowHelper.ThrowEntityTypeHasNoKeyPropertyException(entityTypeMetadata.EntityType); } - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.AppendLine("DELETE FROM"); @@ -938,12 +938,12 @@ private String GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => /// /// The metadata for the entity type to insert. /// The SQL code to insert an entity of the specified type. - private String GetInsertEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => + private string GetInsertEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => this.entityInsertSqlCodePerEntityType.GetOrAdd( entityTypeMetadata.EntityType, _ => { - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.Append("INSERT INTO \""); sqlBuilder.Append(entityTypeMetadata.TableName); @@ -1044,7 +1044,7 @@ private String GetInsertEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => /// /// The metadata for the entity type to update. /// The SQL code to update an entity of the specified type. - private String GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => + private string GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => this.entityUpdateSqlCodePerEntityType.GetOrAdd( entityTypeMetadata.EntityType, _ => @@ -1054,7 +1054,7 @@ private String GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => ThrowHelper.ThrowEntityTypeHasNoKeyPropertyException(entityTypeMetadata.EntityType); } - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.AppendLine("UPDATE"); sqlBuilder.Append(Constants.Indent); @@ -1172,7 +1172,7 @@ private String GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => private void PopulateParametersFromEntityProperties( EntityTypeMetadata entityTypeMetadata, List parameters, - Object entity + object entity ) { ArgumentNullException.ThrowIfNull(parameters); @@ -1195,7 +1195,7 @@ Object entity private static void UpdateDatabaseGeneratedProperties( EntityTypeMetadata entityTypeMetadata, DbParameter[] outputParameters, - Object entity + object entity ) { if (entityTypeMetadata.DatabaseGeneratedProperties.Count > 0) @@ -1218,7 +1218,7 @@ Object entity } private readonly OracleDatabaseAdapter databaseAdapter; - private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); - private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); - private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); } diff --git a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleTemporaryTableBuilder.cs b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleTemporaryTableBuilder.cs index 8df49e7..980b82a 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleTemporaryTableBuilder.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleTemporaryTableBuilder.cs @@ -36,7 +36,7 @@ public OracleTemporaryTableBuilder(OracleDatabaseAdapter databaseAdapter) public TemporaryTableDisposer BuildTemporaryTable( DbConnection connection, DbTransaction? transaction, - String name, + string name, IEnumerable values, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, @@ -131,7 +131,7 @@ public TemporaryTableDisposer BuildTemporaryTable( public async Task BuildTemporaryTableAsync( DbConnection connection, DbTransaction? transaction, - String name, + string name, IEnumerable values, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, @@ -234,14 +234,14 @@ await this.PopulateTemporaryTableAsync( /// The type of objects with which to populate the table. /// The mode to use to serialize values. /// The built SQL code. - private String BuildCreateMultiColumnTemporaryTableSqlCode( - String quotedTableName, + private string BuildCreateMultiColumnTemporaryTableSqlCode( + string quotedTableName, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type objectsType, EnumSerializationMode enumSerializationMode ) { - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.Append("CREATE PRIVATE TEMPORARY TABLE "); sqlBuilder.AppendLine(quotedTableName); @@ -285,15 +285,15 @@ EnumSerializationMode enumSerializationMode /// The type of values with which the table will be populated. /// The mode to use to serialize values. /// The built SQL code. - private String BuildCreateSingleColumnTemporaryTableSqlCode( - String quotedTableName, + private string BuildCreateSingleColumnTemporaryTableSqlCode( + string quotedTableName, IEnumerable values, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, EnumSerializationMode enumSerializationMode ) { - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[100]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[100]); sqlBuilder.Append("CREATE PRIVATE TEMPORARY TABLE"); sqlBuilder.AppendLine(quotedTableName); @@ -303,11 +303,11 @@ EnumSerializationMode enumSerializationMode sqlBuilder.Append(Constants.SingleColumnTemporaryTableColumnName); sqlBuilder.Append("\" "); - if (valuesType == typeof(String)) + if (valuesType == typeof(string)) { var maxLength = 0; - foreach (String? value in values) + foreach (string? value in values) { if (value?.Length > maxLength) { @@ -354,7 +354,7 @@ EnumSerializationMode enumSerializationMode private void PopulateTemporaryTable( OracleConnection connection, OracleTransaction? transaction, - String quotedTableName, + string quotedTableName, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, DbDataReader dataReader, @@ -403,7 +403,7 @@ CancellationToken cancellationToken private async Task PopulateTemporaryTableAsync( OracleConnection connection, OracleTransaction? transaction, - String quotedTableName, + string quotedTableName, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, DbDataReader dataReader, @@ -447,14 +447,14 @@ CancellationToken cancellationToken /// The type of values with which to populate the table. /// The data reader to read data from. /// A tuple containing the insert SQL code and the parameters to use. - private static (String SqlCode, OracleParameter[] Parameters) BuildInsertSqlCode( - String quotedTableName, + private static (string SqlCode, OracleParameter[] Parameters) BuildInsertSqlCode( + string quotedTableName, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, DbDataReader dataReader ) { - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.Append("INSERT INTO "); sqlBuilder.AppendLine(quotedTableName); @@ -554,7 +554,7 @@ [.. EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a /// The connection to use to drop the table. /// The transaction within to drop the table. private static void DropTemporaryTable( - String quotedTableName, + string quotedTableName, OracleConnection connection, OracleTransaction? transaction ) @@ -577,7 +577,7 @@ private static void DropTemporaryTable( /// The transaction within to drop the table. /// A task representing the asynchronous operation. private static async ValueTask DropTemporaryTableAsync( - String quotedTableName, + string quotedTableName, OracleConnection connection, OracleTransaction? transaction ) diff --git a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlDatabaseAdapter.cs b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlDatabaseAdapter.cs index db86d96..a8c3e44 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlDatabaseAdapter.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlDatabaseAdapter.cs @@ -28,7 +28,7 @@ public PostgreSqlDatabaseAdapter() this.temporaryTableBuilder; /// - public void BindParameterValue(DbParameter parameter, Object? value) + public void BindParameterValue(DbParameter parameter, object? value) { ArgumentNullException.ThrowIfNull(parameter); @@ -60,7 +60,7 @@ public void BindParameterValue(DbParameter parameter, Object? value) ); break; - case Byte[]: + case byte[]: parameter.DbType = DbType.Binary; parameter.Value = value; break; @@ -72,11 +72,11 @@ public void BindParameterValue(DbParameter parameter, Object? value) } /// - public String FormatParameterName(String parameterName) => + public string FormatParameterName(string parameterName) => "@" + parameterName; /// - public String GetDataType(Type type, EnumSerializationMode enumSerializationMode) + public string GetDataType(Type type, EnumSerializationMode enumSerializationMode) { ArgumentNullException.ThrowIfNull(type); @@ -94,7 +94,7 @@ public String GetDataType(Type type, EnumSerializationMode enumSerializationMode "integer", _ => - ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode) + ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode) }; } @@ -174,19 +174,19 @@ public NpgsqlDbType GetDbType(Type type, EnumSerializationMode enumSerialization } /// - public String QuoteIdentifier(String identifier) => + public string QuoteIdentifier(string identifier) => "\"" + identifier + "\""; /// - public String QuoteTemporaryTableName(String tableName, DbConnection connection) => + public string QuoteTemporaryTableName(string tableName, DbConnection connection) => "\"" + tableName + "\""; /// - public Boolean SupportsTemporaryTables(DbConnection connection) => + public bool SupportsTemporaryTables(DbConnection connection) => true; /// - public Boolean WasSqlStatementCancelledByCancellationToken( + public bool WasSqlStatementCancelledByCancellationToken( Exception exception, CancellationToken cancellationToken ) @@ -201,40 +201,40 @@ CancellationToken cancellationToken private static readonly Dictionary typeToNpgsqlDbType = new() { - { typeof(Boolean), NpgsqlDbType.Boolean }, - { typeof(Byte), NpgsqlDbType.Smallint }, - { typeof(Byte[]), NpgsqlDbType.Bytea }, - { typeof(Char), NpgsqlDbType.Char }, + { typeof(bool), NpgsqlDbType.Boolean }, + { typeof(byte), NpgsqlDbType.Smallint }, + { typeof(byte[]), NpgsqlDbType.Bytea }, + { typeof(char), NpgsqlDbType.Char }, { typeof(DateOnly), NpgsqlDbType.Date }, { typeof(DateTime), NpgsqlDbType.Timestamp }, - { typeof(Decimal), NpgsqlDbType.Numeric }, - { typeof(Double), NpgsqlDbType.Double }, + { typeof(decimal), NpgsqlDbType.Numeric }, + { typeof(double), NpgsqlDbType.Double }, { typeof(Guid), NpgsqlDbType.Uuid }, - { typeof(Int16), NpgsqlDbType.Smallint }, - { typeof(Int32), NpgsqlDbType.Integer }, - { typeof(Int64), NpgsqlDbType.Bigint }, - { typeof(Single), NpgsqlDbType.Real }, - { typeof(String), NpgsqlDbType.Text }, + { typeof(short), NpgsqlDbType.Smallint }, + { typeof(int), NpgsqlDbType.Integer }, + { typeof(long), NpgsqlDbType.Bigint }, + { typeof(float), NpgsqlDbType.Real }, + { typeof(string), NpgsqlDbType.Text }, { typeof(TimeOnly), NpgsqlDbType.Time }, { typeof(TimeSpan), NpgsqlDbType.Interval } }; - private static readonly Dictionary typeToPostgreSqlDataType = new() + private static readonly Dictionary typeToPostgreSqlDataType = new() { - { typeof(Boolean), "boolean" }, - { typeof(Byte), "smallint" }, - { typeof(Byte[]), "bytea" }, - { typeof(Char), "char(1)" }, + { typeof(bool), "boolean" }, + { typeof(byte), "smallint" }, + { typeof(byte[]), "bytea" }, + { typeof(char), "char(1)" }, { typeof(DateOnly), "date" }, { typeof(DateTime), "timestamp without time zone" }, - { typeof(Decimal), "decimal" }, - { typeof(Double), "double precision" }, + { typeof(decimal), "decimal" }, + { typeof(double), "double precision" }, { typeof(Guid), "uuid" }, - { typeof(Int16), "smallint" }, - { typeof(Int32), "integer" }, - { typeof(Int64), "bigint" }, - { typeof(Single), "real" }, - { typeof(String), "text" }, + { typeof(short), "smallint" }, + { typeof(int), "integer" }, + { typeof(long), "bigint" }, + { typeof(float), "real" }, + { typeof(string), "text" }, { typeof(TimeOnly), "time" }, { typeof(TimeSpan), "interval" } }; diff --git a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlEntityManipulator.cs index 5cf7d77..06528d3 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlEntityManipulator.cs @@ -21,7 +21,7 @@ public PostgreSqlEntityManipulator(PostgreSqlDatabaseAdapter databaseAdapter) => this.databaseAdapter = databaseAdapter; /// - public Int32 DeleteEntities< + public int DeleteEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -84,7 +84,7 @@ CancellationToken cancellationToken } /// - public async Task DeleteEntitiesAsync< + public async Task DeleteEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -148,7 +148,7 @@ CancellationToken cancellationToken } /// - public Int32 DeleteEntity< + public int DeleteEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -199,7 +199,7 @@ CancellationToken cancellationToken } /// - public async Task DeleteEntityAsync< + public async Task DeleteEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -250,7 +250,7 @@ CancellationToken cancellationToken } /// - public Int32 InsertEntities< + public int InsertEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -308,7 +308,7 @@ CancellationToken cancellationToken } /// - public async Task InsertEntitiesAsync< + public async Task InsertEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -374,7 +374,7 @@ await UpdateDatabaseGeneratedPropertiesAsync( } /// - public Int32 InsertEntity< + public int InsertEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -420,7 +420,7 @@ CancellationToken cancellationToken } /// - public async Task InsertEntityAsync< + public async Task InsertEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -470,7 +470,7 @@ await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, } /// - public Int32 UpdateEntities< + public int UpdateEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -541,7 +541,7 @@ CancellationToken cancellationToken } /// - public async Task UpdateEntitiesAsync< + public async Task UpdateEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -620,7 +620,7 @@ await UpdateDatabaseGeneratedPropertiesAsync( } /// - public Int32 UpdateEntity< + public int UpdateEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -679,7 +679,7 @@ CancellationToken cancellationToken } /// - public async Task UpdateEntityAsync< + public async Task UpdateEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -859,7 +859,7 @@ EntityTypeMetadata entityTypeMetadata /// /// The metadata for the entity type to delete. /// The SQL code to delete an entity of the specified type. - private String GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => + private string GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => this.entityDeleteSqlCodePerEntityType.GetOrAdd( entityTypeMetadata.EntityType, _ => @@ -869,7 +869,7 @@ private String GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => ThrowHelper.ThrowEntityTypeHasNoKeyPropertyException(entityTypeMetadata.EntityType); } - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.AppendLine("DELETE FROM"); @@ -914,12 +914,12 @@ private String GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => /// /// The metadata for the entity type to insert. /// The SQL code to insert an entity of the specified type. - private String GetInsertEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => + private string GetInsertEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => this.entityInsertSqlCodePerEntityType.GetOrAdd( entityTypeMetadata.EntityType, _ => { - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.Append("INSERT INTO \""); sqlBuilder.Append(entityTypeMetadata.TableName); @@ -1001,7 +1001,7 @@ private String GetInsertEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => /// /// The metadata for the entity type to update. /// The SQL code to update an entity of the specified type. - private String GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => + private string GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => this.entityUpdateSqlCodePerEntityType.GetOrAdd( entityTypeMetadata.EntityType, _ => @@ -1011,7 +1011,7 @@ private String GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => ThrowHelper.ThrowEntityTypeHasNoKeyPropertyException(entityTypeMetadata.EntityType); } - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.AppendLine("UPDATE"); @@ -1108,7 +1108,7 @@ private String GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => private void PopulateParametersFromEntityProperties( EntityTypeMetadata entityTypeMetadata, List parameters, - Object entity + object entity ) { ArgumentNullException.ThrowIfNull(parameters); @@ -1132,7 +1132,7 @@ Object entity private static void UpdateDatabaseGeneratedProperties( EntityTypeMetadata entityTypeMetadata, DbDataReader reader, - Object entity, + object entity, CancellationToken cancellationToken ) { @@ -1170,7 +1170,7 @@ CancellationToken cancellationToken private static async Task UpdateDatabaseGeneratedPropertiesAsync( EntityTypeMetadata entityTypeMetadata, DbDataReader reader, - Object entity, + object entity, CancellationToken cancellationToken ) { @@ -1198,7 +1198,7 @@ await reader.ReadAsync(cancellationToken).ConfigureAwait(false) } private readonly PostgreSqlDatabaseAdapter databaseAdapter; - private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); - private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); - private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); } diff --git a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlTemporaryTableBuilder.cs b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlTemporaryTableBuilder.cs index d97224c..21f11a2 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlTemporaryTableBuilder.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlTemporaryTableBuilder.cs @@ -35,7 +35,7 @@ public PostgreSqlTemporaryTableBuilder(PostgreSqlDatabaseAdapter databaseAdapter public TemporaryTableDisposer BuildTemporaryTable( DbConnection connection, DbTransaction? transaction, - String name, + string name, IEnumerable values, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, @@ -110,7 +110,7 @@ public TemporaryTableDisposer BuildTemporaryTable( public async Task BuildTemporaryTableAsync( DbConnection connection, DbTransaction? transaction, - String name, + string name, IEnumerable values, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, @@ -196,14 +196,14 @@ await this.PopulateTemporaryTableAsync(npgsqlConnection, name, valuesType, reade /// The type of objects with which to populate the table. /// The mode to use to serialize values. /// The built SQL code. - private String BuildCreateMultiColumnTemporaryTableSqlCode( - String tableName, + private string BuildCreateMultiColumnTemporaryTableSqlCode( + string tableName, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type objectsType, EnumSerializationMode enumSerializationMode ) { - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.Append("CREATE TEMP TABLE \""); sqlBuilder.Append(tableName); @@ -247,14 +247,14 @@ EnumSerializationMode enumSerializationMode /// The type of values with which the table will be populated. /// The mode to use to serialize values. /// The built SQL code. - private String BuildCreateSingleColumnTemporaryTableSqlCode( - String tableName, + private string BuildCreateSingleColumnTemporaryTableSqlCode( + string tableName, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, EnumSerializationMode enumSerializationMode ) { - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[100]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[100]); sqlBuilder.Append("CREATE TEMP TABLE \""); sqlBuilder.Append(tableName); @@ -312,7 +312,7 @@ .. EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a. /// A token that can be used to cancel the operation. private void PopulateTemporaryTable( NpgsqlConnection connection, - String tableName, + string tableName, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, DbDataReader dataReader, @@ -367,7 +367,7 @@ CancellationToken cancellationToken /// A task that represents the asynchronous operation. private async Task PopulateTemporaryTableAsync( NpgsqlConnection connection, - String tableName, + string tableName, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, DbDataReader dataReader, @@ -446,7 +446,7 @@ [.. EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a /// The name of the table to drop. /// The connection to use to drop the table. /// The transaction within to drop the table. - private static void DropTemporaryTable(String name, NpgsqlConnection connection, NpgsqlTransaction? transaction) + private static void DropTemporaryTable(string name, NpgsqlConnection connection, NpgsqlTransaction? transaction) { using var command = connection.CreateCommand(); @@ -466,7 +466,7 @@ private static void DropTemporaryTable(String name, NpgsqlConnection connection, /// The transaction within to drop the table. /// A task representing the asynchronous operation. private static async ValueTask DropTemporaryTableAsync( - String name, + string name, NpgsqlConnection connection, NpgsqlTransaction? transaction ) diff --git a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerDatabaseAdapter.cs b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerDatabaseAdapter.cs index 983df16..6609d92 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerDatabaseAdapter.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerDatabaseAdapter.cs @@ -27,7 +27,7 @@ public SqlServerDatabaseAdapter() this.temporaryTableBuilder; /// - public void BindParameterValue(DbParameter parameter, Object? value) + public void BindParameterValue(DbParameter parameter, object? value) { ArgumentNullException.ThrowIfNull(parameter); @@ -59,7 +59,7 @@ public void BindParameterValue(DbParameter parameter, Object? value) ); break; - case Byte[]: + case byte[]: parameter.DbType = DbType.Binary; parameter.Value = value; break; @@ -71,11 +71,11 @@ public void BindParameterValue(DbParameter parameter, Object? value) } /// - public String FormatParameterName(String parameterName) => + public string FormatParameterName(string parameterName) => "@" + parameterName; /// - public String GetDataType(Type type, EnumSerializationMode enumSerializationMode) + public string GetDataType(Type type, EnumSerializationMode enumSerializationMode) { ArgumentNullException.ThrowIfNull(type); @@ -93,7 +93,7 @@ public String GetDataType(Type type, EnumSerializationMode enumSerializationMode "int", _ => - ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode) + ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode) }; } @@ -110,19 +110,19 @@ public String GetDataType(Type type, EnumSerializationMode enumSerializationMode } /// - public String QuoteIdentifier(String identifier) => + public string QuoteIdentifier(string identifier) => "[" + identifier + "]"; /// - public String QuoteTemporaryTableName(String tableName, DbConnection connection) => + public string QuoteTemporaryTableName(string tableName, DbConnection connection) => "[#" + tableName + "]"; /// - public Boolean SupportsTemporaryTables(DbConnection connection) => + public bool SupportsTemporaryTables(DbConnection connection) => true; /// - public Boolean WasSqlStatementCancelledByCancellationToken( + public bool WasSqlStatementCancelledByCancellationToken( Exception exception, CancellationToken cancellationToken ) @@ -158,24 +158,24 @@ CancellationToken cancellationToken private readonly SqlServerEntityManipulator entityManipulator; private readonly SqlServerTemporaryTableBuilder temporaryTableBuilder; - private static readonly Dictionary typeToSqlDataType = new() + private static readonly Dictionary typeToSqlDataType = new() { - { typeof(Boolean), "bit" }, - { typeof(Byte), "tinyint" }, - { typeof(Byte[]), "varbinary(max)" }, - { typeof(Char), "char(1)" }, + { typeof(bool), "bit" }, + { typeof(byte), "tinyint" }, + { typeof(byte[]), "varbinary(max)" }, + { typeof(char), "char(1)" }, { typeof(DateOnly), "date" }, { typeof(DateTime), "datetime2" }, { typeof(DateTimeOffset), "datetimeoffset" }, - { typeof(Decimal), "decimal(28,10)" }, - { typeof(Double), "float" }, + { typeof(decimal), "decimal(28,10)" }, + { typeof(double), "float" }, { typeof(Guid), "uniqueidentifier" }, - { typeof(Int16), "smallint" }, - { typeof(Int32), "int" }, - { typeof(Int64), "bigint" }, - { typeof(Object), "sql_variant" }, - { typeof(Single), "real" }, - { typeof(String), "nvarchar(max)" }, + { typeof(short), "smallint" }, + { typeof(int), "int" }, + { typeof(long), "bigint" }, + { typeof(object), "sql_variant" }, + { typeof(float), "real" }, + { typeof(string), "nvarchar(max)" }, { typeof(TimeOnly), "time" }, { typeof(TimeSpan), "time" } }; diff --git a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerEntityManipulator.cs index 04b5897..7a0e0f2 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerEntityManipulator.cs @@ -21,7 +21,7 @@ public SqlServerEntityManipulator(SqlServerDatabaseAdapter databaseAdapter) => this.databaseAdapter = databaseAdapter; /// - public Int32 DeleteEntities< + public int DeleteEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -84,7 +84,7 @@ CancellationToken cancellationToken } /// - public async Task DeleteEntitiesAsync< + public async Task DeleteEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -148,7 +148,7 @@ CancellationToken cancellationToken } /// - public Int32 DeleteEntity< + public int DeleteEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -199,7 +199,7 @@ CancellationToken cancellationToken } /// - public async Task DeleteEntityAsync< + public async Task DeleteEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -250,7 +250,7 @@ CancellationToken cancellationToken } /// - public Int32 InsertEntities< + public int InsertEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -308,7 +308,7 @@ CancellationToken cancellationToken } /// - public async Task InsertEntitiesAsync< + public async Task InsertEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -374,7 +374,7 @@ await UpdateDatabaseGeneratedPropertiesAsync( } /// - public Int32 InsertEntity< + public int InsertEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -420,7 +420,7 @@ CancellationToken cancellationToken } /// - public async Task InsertEntityAsync< + public async Task InsertEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -470,7 +470,7 @@ await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, } /// - public Int32 UpdateEntities< + public int UpdateEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -541,7 +541,7 @@ CancellationToken cancellationToken } /// - public async Task UpdateEntitiesAsync< + public async Task UpdateEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -620,7 +620,7 @@ await UpdateDatabaseGeneratedPropertiesAsync( } /// - public Int32 UpdateEntity< + public int UpdateEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -679,7 +679,7 @@ CancellationToken cancellationToken } /// - public async Task UpdateEntityAsync< + public async Task UpdateEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -859,7 +859,7 @@ EntityTypeMetadata entityTypeMetadata /// /// The metadata for the entity type to delete. /// The SQL code to delete an entity of the specified type. - private String GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => + private string GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => this.entityDeleteSqlCodePerEntityType.GetOrAdd( entityTypeMetadata.EntityType, _ => @@ -869,7 +869,7 @@ private String GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => ThrowHelper.ThrowEntityTypeHasNoKeyPropertyException(entityTypeMetadata.EntityType); } - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.AppendLine("DELETE FROM"); @@ -914,12 +914,12 @@ private String GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => /// /// The metadata for the entity type to insert. /// The SQL code to insert an entity of the specified type. - private String GetInsertEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => + private string GetInsertEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => this.entityInsertSqlCodePerEntityType.GetOrAdd( entityTypeMetadata.EntityType, _ => { - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.Append("INSERT INTO ["); sqlBuilder.Append(entityTypeMetadata.TableName); @@ -1001,7 +1001,7 @@ private String GetInsertEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => /// /// The metadata for the entity type to update. /// The SQL code to update an entity of the specified type. - private String GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => + private string GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => this.entityUpdateSqlCodePerEntityType.GetOrAdd( entityTypeMetadata.EntityType, _ => @@ -1011,7 +1011,7 @@ private String GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => ThrowHelper.ThrowEntityTypeHasNoKeyPropertyException(entityTypeMetadata.EntityType); } - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.AppendLine("UPDATE"); @@ -1108,7 +1108,7 @@ private String GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => private void PopulateParametersFromEntityProperties( EntityTypeMetadata entityTypeMetadata, List parameters, - Object entity + object entity ) { ArgumentNullException.ThrowIfNull(parameters); @@ -1132,7 +1132,7 @@ Object entity private static void UpdateDatabaseGeneratedProperties( EntityTypeMetadata entityTypeMetadata, DbDataReader reader, - Object entity, + object entity, CancellationToken cancellationToken ) { @@ -1170,7 +1170,7 @@ CancellationToken cancellationToken private static async Task UpdateDatabaseGeneratedPropertiesAsync( EntityTypeMetadata entityTypeMetadata, DbDataReader reader, - Object entity, + object entity, CancellationToken cancellationToken ) { @@ -1198,7 +1198,7 @@ await reader.ReadAsync(cancellationToken).ConfigureAwait(false) } private readonly SqlServerDatabaseAdapter databaseAdapter; - private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); - private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); - private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); } diff --git a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerTemporaryTableBuilder.cs b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerTemporaryTableBuilder.cs index 8183c12..0b8bfd3 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerTemporaryTableBuilder.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerTemporaryTableBuilder.cs @@ -33,7 +33,7 @@ public SqlServerTemporaryTableBuilder(SqlServerDatabaseAdapter databaseAdapter) public TemporaryTableDisposer BuildTemporaryTable( DbConnection connection, DbTransaction? transaction, - String name, + string name, IEnumerable values, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, @@ -143,7 +143,7 @@ public TemporaryTableDisposer BuildTemporaryTable( public async Task BuildTemporaryTableAsync( DbConnection connection, DbTransaction? transaction, - String name, + string name, IEnumerable values, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, @@ -272,15 +272,15 @@ public async Task BuildTemporaryTableAsync( /// The collation to use for text columns. /// The mode to use to serialize values. /// The built SQL code. - private String BuildCreateMultiColumnTemporaryTableSqlCode( - String tableName, + private string BuildCreateMultiColumnTemporaryTableSqlCode( + string tableName, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type objectsType, - String collation, + string collation, EnumSerializationMode enumSerializationMode ) { - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.Append("CREATE TABLE [#"); sqlBuilder.Append(tableName); @@ -309,7 +309,7 @@ EnumSerializationMode enumSerializationMode sqlBuilder.Append(this.databaseAdapter.GetDataType(propertyType, enumSerializationMode)); if ( - propertyType == typeof(String) + propertyType == typeof(string) || ( propertyType.IsEnumOrNullableEnumType() && @@ -339,16 +339,16 @@ EnumSerializationMode enumSerializationMode /// The collation to use for text columns. /// The mode to use to serialize values. /// The built SQL code. - private String BuildCreateSingleColumnTemporaryTableSqlCode( - String tableName, + private string BuildCreateSingleColumnTemporaryTableSqlCode( + string tableName, IEnumerable values, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, - String collation, + string collation, EnumSerializationMode enumSerializationMode ) { - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[100]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[100]); sqlBuilder.Append("CREATE TABLE [#"); sqlBuilder.Append(tableName); @@ -359,11 +359,11 @@ EnumSerializationMode enumSerializationMode sqlBuilder.Append(Constants.SingleColumnTemporaryTableColumnName); sqlBuilder.Append("] "); - if (valuesType == typeof(String)) + if (valuesType == typeof(string)) { var maxLength = 0; - foreach (String? value in values) + foreach (string? value in values) { if (value?.Length > maxLength) { @@ -394,7 +394,7 @@ EnumSerializationMode enumSerializationMode } if ( - valuesType == typeof(String) + valuesType == typeof(string) || ( valuesType.IsEnumOrNullableEnumType() && @@ -440,7 +440,7 @@ [.. EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a /// The name of the table to drop. /// The connection to use to drop the table. /// The transaction within to drop the table. - private static void DropTemporaryTable(String name, SqlConnection connection, SqlTransaction? transaction) + private static void DropTemporaryTable(string name, SqlConnection connection, SqlTransaction? transaction) { using var command = connection.CreateCommand(); @@ -460,7 +460,7 @@ private static void DropTemporaryTable(String name, SqlConnection connection, Sq /// The transaction within to drop the table. /// A task representing the asynchronous operation. private static async ValueTask DropTemporaryTableAsync( - String name, + string name, SqlConnection connection, SqlTransaction? transaction ) @@ -483,7 +483,7 @@ private static async ValueTask DropTemporaryTableAsync( /// The connection to the database of which to get the collation. /// The database transaction within to perform the operation. /// The collation of the database the specified connection is currently connected to. - private static String GetCurrentDatabaseCollation( + private static string GetCurrentDatabaseCollation( SqlConnection connection, SqlTransaction? transaction = null ) => @@ -498,7 +498,7 @@ private static String GetCurrentDatabaseCollation( DbConnectionExtensions.OnBeforeExecutingCommand(command, []); - return (String)command.ExecuteScalar()!; + return (string)command.ExecuteScalar()!; }, (connection, transaction) ); @@ -513,7 +513,7 @@ private static String GetCurrentDatabaseCollation( /// will contain the collation of the database the specified connection is /// currently connected to. /// - private static async ValueTask GetCurrentDatabaseCollationAsync( + private static async ValueTask GetCurrentDatabaseCollationAsync( SqlConnection connection, SqlTransaction? transaction = null ) @@ -532,16 +532,16 @@ private static async ValueTask GetCurrentDatabaseCollationAsync( DbConnectionExtensions.OnBeforeExecutingCommand(command, []); - collation = (String)(await command.ExecuteScalarAsync().ConfigureAwait(false))!; + collation = (string)(await command.ExecuteScalarAsync().ConfigureAwait(false))!; return databaseCollationPerDatabase.GetOrAdd((connection.DataSource, connection.Database), collation); } private readonly SqlServerDatabaseAdapter databaseAdapter; - private const String GetCurrentDatabaseCollationQuery = + private const string GetCurrentDatabaseCollationQuery = "SELECT CONVERT (VARCHAR(256), DATABASEPROPERTYEX(DB_NAME(), 'collation'))"; - private static readonly ConcurrentDictionary<(String DataSource, String Database), String> + private static readonly ConcurrentDictionary<(string DataSource, string Database), string> databaseCollationPerDatabase = []; } diff --git a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteDatabaseAdapter.cs b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteDatabaseAdapter.cs index 00b0a48..efa7d59 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteDatabaseAdapter.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteDatabaseAdapter.cs @@ -27,7 +27,7 @@ public SqliteDatabaseAdapter() this.temporaryTableBuilder; /// - public void BindParameterValue(DbParameter parameter, Object? value) + public void BindParameterValue(DbParameter parameter, object? value) { ArgumentNullException.ThrowIfNull(parameter); @@ -59,7 +59,7 @@ public void BindParameterValue(DbParameter parameter, Object? value) ); break; - case Byte[]: + case byte[]: parameter.DbType = DbType.Binary; parameter.Value = value; break; @@ -71,11 +71,11 @@ public void BindParameterValue(DbParameter parameter, Object? value) } /// - public String FormatParameterName(String parameterName) => + public string FormatParameterName(string parameterName) => "@" + parameterName; /// - public String GetDataType(Type type, EnumSerializationMode enumSerializationMode) + public string GetDataType(Type type, EnumSerializationMode enumSerializationMode) { ArgumentNullException.ThrowIfNull(type); @@ -93,7 +93,7 @@ public String GetDataType(Type type, EnumSerializationMode enumSerializationMode "INTEGER", _ => - ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode) + ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode) }; } @@ -110,19 +110,19 @@ public String GetDataType(Type type, EnumSerializationMode enumSerializationMode } /// - public String QuoteIdentifier(String identifier) => + public string QuoteIdentifier(string identifier) => "\"" + identifier + "\""; /// - public String QuoteTemporaryTableName(String tableName, DbConnection connection) => + public string QuoteTemporaryTableName(string tableName, DbConnection connection) => "temp.\"" + tableName + "\""; /// - public Boolean SupportsTemporaryTables(DbConnection connection) => + public bool SupportsTemporaryTables(DbConnection connection) => true; /// - public Boolean WasSqlStatementCancelledByCancellationToken(Exception exception, CancellationToken cancellationToken) + public bool WasSqlStatementCancelledByCancellationToken(Exception exception, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(exception); @@ -133,23 +133,23 @@ public Boolean WasSqlStatementCancelledByCancellationToken(Exception exception, private readonly SqliteEntityManipulator entityManipulator; private readonly SqliteTemporaryTableBuilder temporaryTableBuilder; - private static readonly Dictionary typeToSqliteDataType = new() + private static readonly Dictionary typeToSqliteDataType = new() { - { typeof(Boolean), "INTEGER" }, - { typeof(Byte), "INTEGER" }, - { typeof(Byte[]), "BLOB" }, - { typeof(Char), "TEXT" }, + { typeof(bool), "INTEGER" }, + { typeof(byte), "INTEGER" }, + { typeof(byte[]), "BLOB" }, + { typeof(char), "TEXT" }, { typeof(DateOnly), "TEXT" }, { typeof(DateTime), "TEXT" }, { typeof(DateTimeOffset), "TEXT" }, - { typeof(Decimal), "TEXT" }, - { typeof(Double), "REAL" }, + { typeof(decimal), "TEXT" }, + { typeof(double), "REAL" }, { typeof(Guid), "TEXT" }, - { typeof(Int16), "INTEGER" }, - { typeof(Int32), "INTEGER" }, - { typeof(Int64), "INTEGER" }, - { typeof(Single), "REAL" }, - { typeof(String), "TEXT" }, + { typeof(short), "INTEGER" }, + { typeof(int), "INTEGER" }, + { typeof(long), "INTEGER" }, + { typeof(float), "REAL" }, + { typeof(string), "TEXT" }, { typeof(TimeOnly), "TEXT" }, { typeof(TimeSpan), "TEXT" } }; diff --git a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteEntityManipulator.cs index 080c8b9..8a733b6 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteEntityManipulator.cs @@ -21,7 +21,7 @@ public SqliteEntityManipulator(SqliteDatabaseAdapter databaseAdapter) => this.databaseAdapter = databaseAdapter; /// - public Int32 DeleteEntities< + public int DeleteEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -84,7 +84,7 @@ CancellationToken cancellationToken } /// - public async Task DeleteEntitiesAsync< + public async Task DeleteEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -148,7 +148,7 @@ CancellationToken cancellationToken } /// - public Int32 DeleteEntity< + public int DeleteEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -199,7 +199,7 @@ CancellationToken cancellationToken } /// - public async Task DeleteEntityAsync< + public async Task DeleteEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -250,7 +250,7 @@ CancellationToken cancellationToken } /// - public Int32 InsertEntities< + public int InsertEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -308,7 +308,7 @@ CancellationToken cancellationToken } /// - public async Task InsertEntitiesAsync< + public async Task InsertEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -374,7 +374,7 @@ await UpdateDatabaseGeneratedPropertiesAsync( } /// - public Int32 InsertEntity< + public int InsertEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -420,7 +420,7 @@ CancellationToken cancellationToken } /// - public async Task InsertEntityAsync< + public async Task InsertEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -470,7 +470,7 @@ await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, } /// - public Int32 UpdateEntities< + public int UpdateEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -542,7 +542,7 @@ CancellationToken cancellationToken } /// - public async Task UpdateEntitiesAsync< + public async Task UpdateEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -622,7 +622,7 @@ await UpdateDatabaseGeneratedPropertiesAsync( } /// - public Int32 UpdateEntity< + public int UpdateEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -682,7 +682,7 @@ CancellationToken cancellationToken } /// - public async Task UpdateEntityAsync< + public async Task UpdateEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -863,7 +863,7 @@ EntityTypeMetadata entityTypeMetadata /// /// The metadata for the entity type to delete. /// The SQL code to delete an entity of the specified type. - private String GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => + private string GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => this.entityDeleteSqlCodePerEntityType.GetOrAdd( entityTypeMetadata.EntityType, _ => @@ -873,7 +873,7 @@ private String GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => ThrowHelper.ThrowEntityTypeHasNoKeyPropertyException(entityTypeMetadata.EntityType); } - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.AppendLine("DELETE FROM"); @@ -918,12 +918,12 @@ private String GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => /// /// The metadata for the entity type to insert. /// The SQL code to insert an entity of the specified type. - private String GetInsertEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => + private string GetInsertEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => this.entityInsertSqlCodePerEntityType.GetOrAdd( entityTypeMetadata.EntityType, _ => { - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.Append("INSERT INTO \""); sqlBuilder.Append(entityTypeMetadata.TableName); @@ -1049,7 +1049,7 @@ private String GetInsertEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => /// /// The metadata for the entity type to update. /// The SQL code to update an entity of the specified type. - private String GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => + private string GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => this.entityUpdateSqlCodePerEntityType.GetOrAdd( entityTypeMetadata.EntityType, _ => @@ -1059,7 +1059,7 @@ private String GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => ThrowHelper.ThrowEntityTypeHasNoKeyPropertyException(entityTypeMetadata.EntityType); } - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.AppendLine("UPDATE"); @@ -1198,7 +1198,7 @@ .. entityTypeMetadata.ConcurrencyTokenProperties private void PopulateParametersFromEntityProperties( EntityTypeMetadata entityTypeMetadata, List parameters, - Object entity + object entity ) { ArgumentNullException.ThrowIfNull(parameters); @@ -1222,7 +1222,7 @@ Object entity private static void UpdateDatabaseGeneratedProperties( EntityTypeMetadata entityTypeMetadata, DbDataReader reader, - Object entity, + object entity, CancellationToken cancellationToken ) { @@ -1260,7 +1260,7 @@ CancellationToken cancellationToken private static async Task UpdateDatabaseGeneratedPropertiesAsync( EntityTypeMetadata entityTypeMetadata, DbDataReader reader, - Object entity, + object entity, CancellationToken cancellationToken ) { @@ -1288,7 +1288,7 @@ await reader.ReadAsync(cancellationToken).ConfigureAwait(false) } private readonly SqliteDatabaseAdapter databaseAdapter; - private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); - private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); - private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); } diff --git a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteTemporaryTableBuilder.cs b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteTemporaryTableBuilder.cs index 45d7577..4138d47 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteTemporaryTableBuilder.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteTemporaryTableBuilder.cs @@ -34,7 +34,7 @@ public SqliteTemporaryTableBuilder(SqliteDatabaseAdapter databaseAdapter) public TemporaryTableDisposer BuildTemporaryTable( DbConnection connection, DbTransaction? transaction, - String name, + string name, IEnumerable values, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, @@ -109,7 +109,7 @@ public TemporaryTableDisposer BuildTemporaryTable( public async Task BuildTemporaryTableAsync( DbConnection connection, DbTransaction? transaction, - String name, + string name, IEnumerable values, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, @@ -202,14 +202,14 @@ await PopulateTemporaryTableAsync( /// The type of objects with which to populate the table. /// The mode to use to serialize values. /// The built SQL code. - private String BuildCreateMultiColumnTemporaryTableSqlCode( - String tableName, + private string BuildCreateMultiColumnTemporaryTableSqlCode( + string tableName, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type objectsType, EnumSerializationMode enumSerializationMode ) { - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.Append("CREATE TEMP TABLE \""); sqlBuilder.Append(tableName); @@ -253,14 +253,14 @@ EnumSerializationMode enumSerializationMode /// The type of values with which the table will be populated. /// The mode to use to serialize values. /// The built SQL code. - private String BuildCreateSingleColumnTemporaryTableSqlCode( - String tableName, + private string BuildCreateSingleColumnTemporaryTableSqlCode( + string tableName, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, EnumSerializationMode enumSerializationMode ) { - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[100]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[100]); sqlBuilder.Append("CREATE TEMP TABLE \""); sqlBuilder.Append(tableName); @@ -283,14 +283,14 @@ EnumSerializationMode enumSerializationMode /// The type of values with which to populate the table. /// The data reader to read data from. /// A tuple containing the insert SQL code and the parameters to use. - private static (String SqlCode, SqliteParameter[] Parameters) BuildInsertSqlCode( - String tableName, + private static (string SqlCode, SqliteParameter[] Parameters) BuildInsertSqlCode( + string tableName, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, DbDataReader dataReader ) { - using var sqlBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); sqlBuilder.Append("INSERT INTO temp.\""); sqlBuilder.Append(tableName); @@ -388,7 +388,7 @@ [.. EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a /// The name of the table to drop. /// The connection to use to drop the table. /// The transaction within to drop the table. - private static void DropTemporaryTable(String name, SqliteConnection connection, SqliteTransaction? transaction) + private static void DropTemporaryTable(string name, SqliteConnection connection, SqliteTransaction? transaction) { using var command = connection.CreateCommand(); @@ -408,7 +408,7 @@ private static void DropTemporaryTable(String name, SqliteConnection connection, /// The transaction within to drop the table. /// A task representing the asynchronous operation. private static async ValueTask DropTemporaryTableAsync( - String name, + string name, SqliteConnection connection, SqliteTransaction? transaction ) @@ -437,7 +437,7 @@ private static async ValueTask DropTemporaryTableAsync( private static void PopulateTemporaryTable( SqliteConnection connection, SqliteTransaction? transaction, - String tableName, + string tableName, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, DbDataReader dataReader, @@ -493,7 +493,7 @@ CancellationToken cancellationToken private static async Task PopulateTemporaryTableAsync( SqliteConnection connection, SqliteTransaction? transaction, - String tableName, + string tableName, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, DbDataReader dataReader, diff --git a/src/DbConnectionPlus/Configuration/DbConnectionPlusConfiguration.cs b/src/DbConnectionPlus/Configuration/DbConnectionPlusConfiguration.cs index bd68fdd..ae151ee 100644 --- a/src/DbConnectionPlus/Configuration/DbConnectionPlusConfiguration.cs +++ b/src/DbConnectionPlus/Configuration/DbConnectionPlusConfiguration.cs @@ -186,5 +186,5 @@ private void EnsureNotFrozen() private readonly Dictionary databaseAdapters = []; private readonly Dictionary entityTypeBuilders = []; - private Boolean isFrozen; + private bool isFrozen; } diff --git a/src/DbConnectionPlus/Configuration/EntityPropertyBuilder.cs b/src/DbConnectionPlus/Configuration/EntityPropertyBuilder.cs index 3a8e929..b2987a3 100644 --- a/src/DbConnectionPlus/Configuration/EntityPropertyBuilder.cs +++ b/src/DbConnectionPlus/Configuration/EntityPropertyBuilder.cs @@ -25,7 +25,7 @@ public sealed class EntityPropertyBuilder : IEntityPropertyBuilder /// /// /// is whitespace. - internal EntityPropertyBuilder(IEntityTypeBuilder entityTypeBuilder, String propertyName) + internal EntityPropertyBuilder(IEntityTypeBuilder entityTypeBuilder, string propertyName) { ArgumentNullException.ThrowIfNull(entityTypeBuilder); ArgumentException.ThrowIfNullOrWhiteSpace(propertyName); @@ -43,7 +43,7 @@ internal EntityPropertyBuilder(IEntityTypeBuilder entityTypeBuilder, String prop /// The configuration of DbConnectionPlus is already frozen and can no longer be modified. /// // ReSharper disable once ParameterHidesMember - public EntityPropertyBuilder HasColumnName(String columnName) + public EntityPropertyBuilder HasColumnName(string columnName) { this.EnsureNotFrozen(); @@ -168,31 +168,31 @@ public EntityPropertyBuilder IsRowVersion() } /// - String? IEntityPropertyBuilder.ColumnName => this.columnName; + string? IEntityPropertyBuilder.ColumnName => this.columnName; /// void IFreezable.Freeze() => this.isFrozen = true; /// - Boolean IEntityPropertyBuilder.IsComputed => this.isComputed; + bool IEntityPropertyBuilder.IsComputed => this.isComputed; /// - Boolean IEntityPropertyBuilder.IsConcurrencyToken => this.isConcurrencyToken; + bool IEntityPropertyBuilder.IsConcurrencyToken => this.isConcurrencyToken; /// - Boolean IEntityPropertyBuilder.IsIdentity => this.isIdentity; + bool IEntityPropertyBuilder.IsIdentity => this.isIdentity; /// - Boolean IEntityPropertyBuilder.IsIgnored => this.isIgnored; + bool IEntityPropertyBuilder.IsIgnored => this.isIgnored; /// - Boolean IEntityPropertyBuilder.IsKey => this.isKey; + bool IEntityPropertyBuilder.IsKey => this.isKey; /// - Boolean IEntityPropertyBuilder.IsRowVersion => this.isRowVersion; + bool IEntityPropertyBuilder.IsRowVersion => this.isRowVersion; /// - String IEntityPropertyBuilder.PropertyName => this.propertyName; + string IEntityPropertyBuilder.PropertyName => this.propertyName; /// /// Ensures this instance is not frozen. @@ -207,14 +207,14 @@ private void EnsureNotFrozen() } private readonly IEntityTypeBuilder entityTypeBuilder; - private readonly String propertyName; - - private String? columnName; - private Boolean isComputed; - private Boolean isConcurrencyToken; - private Boolean isFrozen; - private Boolean isIdentity; - private Boolean isIgnored; - private Boolean isKey; - private Boolean isRowVersion; + private readonly string propertyName; + + private string? columnName; + private bool isComputed; + private bool isConcurrencyToken; + private bool isFrozen; + private bool isIdentity; + private bool isIgnored; + private bool isKey; + private bool isRowVersion; } diff --git a/src/DbConnectionPlus/Configuration/EntityTypeBuilder.cs b/src/DbConnectionPlus/Configuration/EntityTypeBuilder.cs index b4f0f97..6434131 100644 --- a/src/DbConnectionPlus/Configuration/EntityTypeBuilder.cs +++ b/src/DbConnectionPlus/Configuration/EntityTypeBuilder.cs @@ -50,7 +50,7 @@ public EntityPropertyBuilder Property(Expression // ReSharper disable once ParameterHidesMember - public EntityTypeBuilder ToTable(String tableName) + public EntityTypeBuilder ToTable(string tableName) { this.EnsureNotFrozen(); @@ -74,11 +74,11 @@ void IFreezable.Freeze() } /// - IReadOnlyDictionary IEntityTypeBuilder.PropertyBuilders => + IReadOnlyDictionary IEntityTypeBuilder.PropertyBuilders => this.propertyBuilders; /// - String? IEntityTypeBuilder.TableName => this.tableName; + string? IEntityTypeBuilder.TableName => this.tableName; /// /// Ensures this instance is not frozen. @@ -100,7 +100,7 @@ private void EnsureNotFrozen() /// /// is not a valid property access expression. /// - private static String GetPropertyNameFromPropertyExpression(LambdaExpression propertyExpression) => + private static string GetPropertyNameFromPropertyExpression(LambdaExpression propertyExpression) => propertyExpression.Body is MemberExpression { Member: PropertyInfo propertyInfo } ? propertyInfo.Name : throw new ArgumentException( @@ -109,7 +109,7 @@ private static String GetPropertyNameFromPropertyExpression(LambdaExpression pro nameof(propertyExpression) ); - private readonly ConcurrentDictionary propertyBuilders = new(); - private Boolean isFrozen; - private String? tableName; + private readonly ConcurrentDictionary propertyBuilders = new(); + private bool isFrozen; + private string? tableName; } diff --git a/src/DbConnectionPlus/Configuration/IEntityPropertyBuilder.cs b/src/DbConnectionPlus/Configuration/IEntityPropertyBuilder.cs index 149b51b..477fa4a 100644 --- a/src/DbConnectionPlus/Configuration/IEntityPropertyBuilder.cs +++ b/src/DbConnectionPlus/Configuration/IEntityPropertyBuilder.cs @@ -8,40 +8,40 @@ internal interface IEntityPropertyBuilder : IFreezable /// /// The name of the column the property is mapped to. /// - internal String? ColumnName { get; } + internal string? ColumnName { get; } /// /// Determines whether the property is mapped to a computed database column. /// - internal Boolean IsComputed { get; } + internal bool IsComputed { get; } /// /// Determines whether the property participates in optimistic concurrency checks. /// - internal Boolean IsConcurrencyToken { get; } + internal bool IsConcurrencyToken { get; } /// /// Determines whether the property is mapped to an identity database column. /// - internal Boolean IsIdentity { get; } + internal bool IsIdentity { get; } /// /// Determines whether the property is not mapped to a database column. /// - internal Boolean IsIgnored { get; } + internal bool IsIgnored { get; } /// /// Determines whether the property is mapped to a key database column. /// - internal Boolean IsKey { get; } + internal bool IsKey { get; } /// /// Determines whether the property is a row version used for concurrency control. /// - internal Boolean IsRowVersion { get; } + internal bool IsRowVersion { get; } /// /// The name of the property being configured. /// - internal String PropertyName { get; } + internal string PropertyName { get; } } diff --git a/src/DbConnectionPlus/Configuration/IEntityTypeBuilder.cs b/src/DbConnectionPlus/Configuration/IEntityTypeBuilder.cs index cbaa2fe..4c36123 100644 --- a/src/DbConnectionPlus/Configuration/IEntityTypeBuilder.cs +++ b/src/DbConnectionPlus/Configuration/IEntityTypeBuilder.cs @@ -13,10 +13,10 @@ internal interface IEntityTypeBuilder : IFreezable /// /// The property builders associated with the entity type. /// - internal IReadOnlyDictionary PropertyBuilders { get; } + internal IReadOnlyDictionary PropertyBuilders { get; } /// /// The name of the table the entity type is mapped to. /// - internal String? TableName { get; } + internal string? TableName { get; } } diff --git a/src/DbConnectionPlus/Converters/EnumConverter.cs b/src/DbConnectionPlus/Converters/EnumConverter.cs index 11b1db8..3d4637a 100644 --- a/src/DbConnectionPlus/Converters/EnumConverter.cs +++ b/src/DbConnectionPlus/Converters/EnumConverter.cs @@ -82,7 +82,7 @@ internal static class EnumConverter /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static TTarget? ConvertValueToEnumMember(Object? value) + internal static TTarget? ConvertValueToEnumMember(object? value) { var targetType = typeof(TTarget); @@ -106,11 +106,11 @@ internal static class EnumConverter case TTarget alreadyTargetTypeValue: return alreadyTargetTypeValue; - case String stringValue when String.IsNullOrWhiteSpace(stringValue): + case string stringValue when string.IsNullOrWhiteSpace(stringValue): ThrowCouldNotConvertEmptyOrWhitespaceStringToEnumTypeException(targetType); return default; // Just to satisfy the compiler. - case String stringValue: + case string stringValue: if (!Enum.TryParse(effectiveTargetType, stringValue, true, out var result)) { ThrowCouldNotConvertStringToEnumTypeException(stringValue, targetType); @@ -118,7 +118,7 @@ internal static class EnumConverter return (TTarget?)result; - case Byte or SByte or Int16 or UInt16 or Int32 or UInt32 or Int64 or UInt64 or Double or Single or Decimal: + case byte or sbyte or short or ushort or int or uint or long or ulong or double or float or decimal: var enumUnderlyingType = Enum.GetUnderlyingType(effectiveTargetType); var valueConvertedToEnumUnderlyingType = Convert.ChangeType( @@ -218,7 +218,7 @@ internal static class EnumConverter /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Object? ConvertValueToEnumMember(Object? value, Type targetType) + internal static object? ConvertValueToEnumMember(object? value, Type targetType) { ArgumentNullException.ThrowIfNull(targetType); @@ -242,11 +242,11 @@ internal static class EnumConverter case not null when value.GetType().IsAssignableTo(effectiveTargetType): return value; - case String stringValue when String.IsNullOrWhiteSpace(stringValue): + case string stringValue when string.IsNullOrWhiteSpace(stringValue): ThrowCouldNotConvertEmptyOrWhitespaceStringToEnumTypeException(targetType); return null; // Just to satisfy the compiler. - case String stringValue: + case string stringValue: if (!Enum.TryParse(effectiveTargetType, stringValue, true, out var result)) { ThrowCouldNotConvertStringToEnumTypeException(stringValue, targetType); @@ -254,7 +254,7 @@ internal static class EnumConverter return result; - case Byte or SByte or Int16 or UInt16 or Int32 or UInt32 or Int64 or UInt64 or Double or Single or Decimal: + case byte or sbyte or short or ushort or int or uint or long or ulong or double or float or decimal: var enumUnderlyingType = Enum.GetUnderlyingType(effectiveTargetType); var valueConvertedToEnumUnderlyingType = Convert.ChangeType( @@ -300,7 +300,7 @@ private static void ThrowCouldNotConvertNullToNonNullableEnumTypeException(Type [MethodImpl(MethodImplOptions.NoInlining)] [DoesNotReturn] private static void - ThrowCouldNotConvertNumericValueToEnumType(Object value, Type enumType) => + ThrowCouldNotConvertNumericValueToEnumType(object value, Type enumType) => throw new InvalidCastException( $"Could not convert the value {value.ToDebugString()} to an enum member of the type {enumType}. That " + "value does not match any of the values of the enum's members." @@ -309,7 +309,7 @@ private static void [MethodImpl(MethodImplOptions.NoInlining)] [DoesNotReturn] private static void ThrowCouldNotConvertStringToEnumTypeException( - String value, + string value, Type enumType ) => throw new InvalidCastException( @@ -319,7 +319,7 @@ Type enumType [MethodImpl(MethodImplOptions.NoInlining)] [DoesNotReturn] - private static void ThrowTypeIsNeitherEnumNorNullableEnumTypeException(Object? value, Type enumType) => + private static void ThrowTypeIsNeitherEnumNorNullableEnumTypeException(object? value, Type enumType) => throw new ArgumentException( $"Could not convert the value {value.ToDebugString()} to an enum member of the type {enumType}, because " + $"the type {enumType} is not an enum type.", @@ -329,7 +329,7 @@ private static void ThrowTypeIsNeitherEnumNorNullableEnumTypeException(Object? v [MethodImpl(MethodImplOptions.NoInlining)] [DoesNotReturn] private static void ThrowValueIsNeitherEnumValueNorStringNorNumericValueException( - Object? value, + object? value, Type originalEnumType ) => throw new InvalidCastException( diff --git a/src/DbConnectionPlus/Converters/EnumSerializer.cs b/src/DbConnectionPlus/Converters/EnumSerializer.cs index 48a1983..99af75f 100644 --- a/src/DbConnectionPlus/Converters/EnumSerializer.cs +++ b/src/DbConnectionPlus/Converters/EnumSerializer.cs @@ -21,7 +21,7 @@ internal static class EnumSerializer /// is not a valid value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Object SerializeEnum(Enum enumValue, EnumSerializationMode serializationMode) + internal static object SerializeEnum(Enum enumValue, EnumSerializationMode serializationMode) { ArgumentNullException.ThrowIfNull(enumValue); @@ -34,7 +34,7 @@ internal static Object SerializeEnum(Enum enumValue, EnumSerializationMode seria Convert.ToInt32(enumValue, CultureInfo.InvariantCulture), _ => - ThrowHelper.ThrowInvalidEnumSerializationModeException(serializationMode) + ThrowHelper.ThrowInvalidEnumSerializationModeException(serializationMode) }; } } diff --git a/src/DbConnectionPlus/Converters/ValueConverter.cs b/src/DbConnectionPlus/Converters/ValueConverter.cs index 635be2a..afc6d4e 100644 --- a/src/DbConnectionPlus/Converters/ValueConverter.cs +++ b/src/DbConnectionPlus/Converters/ValueConverter.cs @@ -35,7 +35,7 @@ internal static class ValueConverter /// /// /// - internal static Boolean CanConvert(Type sourceType, Type targetType) + internal static bool CanConvert(Type sourceType, Type targetType) { ArgumentNullException.ThrowIfNull(sourceType); ArgumentNullException.ThrowIfNull(targetType); @@ -45,7 +45,7 @@ internal static Boolean CanConvert(Type sourceType, Type targetType) if ( effectiveSourceType == effectiveTargetType || - effectiveTargetType == typeof(Object) + effectiveTargetType == typeof(object) ) { // Conversion to same type or to Object is always possible. @@ -87,14 +87,14 @@ internal static Boolean CanConvert(Type sourceType, Type targetType) /// /// /// - /// is or and + /// is or and /// is a string that has a length other than 1. /// /// /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static TTarget? ConvertValueToType(Object? value) + internal static TTarget? ConvertValueToType(object? value) { var targetType = typeof(TTarget); @@ -115,23 +115,23 @@ internal static Boolean CanConvert(Type sourceType, Type targetType) case TTarget alreadyTargetTypeValue: return alreadyTargetTypeValue; - case String stringValue when effectiveTargetType == typeof(Guid): + case string stringValue when effectiveTargetType == typeof(Guid): if (!Guid.TryParse(stringValue, out var guidResult)) { ThrowCouldNotConvertValueToTargetTypeException(stringValue, targetType); } - return (TTarget)(Object)guidResult; + return (TTarget)(object)guidResult; - case String stringValue when effectiveTargetType == typeof(TimeSpan): + case string stringValue when effectiveTargetType == typeof(TimeSpan): if (!TimeSpan.TryParse(stringValue, CultureInfo.InvariantCulture, out var timeSpanResult)) { ThrowCouldNotConvertValueToTargetTypeException(stringValue, targetType); } - return (TTarget)(Object)timeSpanResult; + return (TTarget)(object)timeSpanResult; - case String stringValue when effectiveTargetType == typeof(Char): + case string stringValue when effectiveTargetType == typeof(char): if (stringValue.Length != 1) { ThrowCouldNotConvertNonSingleCharStringToCharException( @@ -140,61 +140,61 @@ internal static Boolean CanConvert(Type sourceType, Type targetType) ); } - return (TTarget)(Object)stringValue[0]; + return (TTarget)(object)stringValue[0]; - case String stringValue when effectiveTargetType == typeof(DateTimeOffset): + case string stringValue when effectiveTargetType == typeof(DateTimeOffset): if (!DateTimeOffset.TryParse(stringValue, CultureInfo.InvariantCulture, out var dateTimeOffsetResult)) { ThrowCouldNotConvertValueToTargetTypeException(stringValue, targetType); } - return (TTarget)(Object)dateTimeOffsetResult; + return (TTarget)(object)dateTimeOffsetResult; - case String stringValue when effectiveTargetType == typeof(DateOnly): + case string stringValue when effectiveTargetType == typeof(DateOnly): if (!DateOnly.TryParse(stringValue, CultureInfo.InvariantCulture, out var dateOnlyResult)) { ThrowCouldNotConvertValueToTargetTypeException(stringValue, targetType); } - return (TTarget)(Object)dateOnlyResult; + return (TTarget)(object)dateOnlyResult; - case String stringValue when effectiveTargetType == typeof(TimeOnly): + case string stringValue when effectiveTargetType == typeof(TimeOnly): if (!TimeOnly.TryParse(stringValue, CultureInfo.InvariantCulture, out var timeOnlyResult)) { ThrowCouldNotConvertValueToTargetTypeException(stringValue, targetType); } - return (TTarget)(Object)timeOnlyResult; + return (TTarget)(object)timeOnlyResult; - case Guid guid when targetType == typeof(String): - return (TTarget)(Object)guid.ToString("D"); + case Guid guid when targetType == typeof(string): + return (TTarget)(object)guid.ToString("D"); - case Guid guid when targetType == typeof(Byte[]): - return (TTarget)(Object)guid.ToByteArray(); + case Guid guid when targetType == typeof(byte[]): + return (TTarget)(object)guid.ToByteArray(); - case DateTime dateTime when targetType == typeof(String): - return (TTarget)(Object)dateTime.ToString("O", CultureInfo.InvariantCulture); + case DateTime dateTime when targetType == typeof(string): + return (TTarget)(object)dateTime.ToString("O", CultureInfo.InvariantCulture); case DateTime dateTime when effectiveTargetType == typeof(DateOnly): - return (TTarget)(Object)DateOnly.FromDateTime(dateTime); + return (TTarget)(object)DateOnly.FromDateTime(dateTime); - case TimeSpan timeSpan when targetType == typeof(String): - return (TTarget)(Object)timeSpan.ToString("g", CultureInfo.InvariantCulture); + case TimeSpan timeSpan when targetType == typeof(string): + return (TTarget)(object)timeSpan.ToString("g", CultureInfo.InvariantCulture); case TimeSpan timeSpan when effectiveTargetType == typeof(TimeOnly): - return (TTarget)(Object)TimeOnly.FromTimeSpan(timeSpan); + return (TTarget)(object)TimeOnly.FromTimeSpan(timeSpan); - case Byte[] bytes when effectiveTargetType == typeof(Guid): - return (TTarget)(Object)new Guid(bytes); + case byte[] bytes when effectiveTargetType == typeof(Guid): + return (TTarget)(object)new Guid(bytes); - case DateTimeOffset dateTimeOffset when targetType == typeof(String): - return (TTarget)(Object)dateTimeOffset.ToString("O", CultureInfo.InvariantCulture); + case DateTimeOffset dateTimeOffset when targetType == typeof(string): + return (TTarget)(object)dateTimeOffset.ToString("O", CultureInfo.InvariantCulture); - case DateOnly dateOnly when targetType == typeof(String): - return (TTarget)(Object)dateOnly.ToString("O", CultureInfo.InvariantCulture); + case DateOnly dateOnly when targetType == typeof(string): + return (TTarget)(object)dateOnly.ToString("O", CultureInfo.InvariantCulture); - case TimeOnly timeOnly when targetType == typeof(String): - return (TTarget)(Object)timeOnly.ToString("O", CultureInfo.InvariantCulture); + case TimeOnly timeOnly when targetType == typeof(string): + return (TTarget)(object)timeOnly.ToString("O", CultureInfo.InvariantCulture); default: if (effectiveTargetType.IsEnum) @@ -247,14 +247,14 @@ exception is ArgumentException or InvalidCastException or FormatException or Ove /// /// /// - /// is or and + /// is or and /// is a string that has a length other than 1. /// /// /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Object? ConvertValueToType(Object? value, Type targetType) + internal static object? ConvertValueToType(object? value, Type targetType) { ArgumentNullException.ThrowIfNull(targetType); @@ -275,7 +275,7 @@ exception is ArgumentException or InvalidCastException or FormatException or Ove case not null when value.GetType().IsAssignableTo(effectiveTargetType): return value; - case String stringValue when effectiveTargetType == typeof(Guid): + case string stringValue when effectiveTargetType == typeof(Guid): if (!Guid.TryParse(stringValue, out var guidResult)) { ThrowCouldNotConvertValueToTargetTypeException(stringValue, targetType); @@ -283,7 +283,7 @@ exception is ArgumentException or InvalidCastException or FormatException or Ove return guidResult; - case String stringValue when effectiveTargetType == typeof(TimeSpan): + case string stringValue when effectiveTargetType == typeof(TimeSpan): if (!TimeSpan.TryParse(stringValue, CultureInfo.InvariantCulture, out var timeSpanResult)) { ThrowCouldNotConvertValueToTargetTypeException(stringValue, targetType); @@ -291,7 +291,7 @@ exception is ArgumentException or InvalidCastException or FormatException or Ove return timeSpanResult; - case String stringValue when effectiveTargetType == typeof(Char): + case string stringValue when effectiveTargetType == typeof(char): if (stringValue.Length != 1) { ThrowCouldNotConvertNonSingleCharStringToCharException( @@ -302,7 +302,7 @@ exception is ArgumentException or InvalidCastException or FormatException or Ove return stringValue[0]; - case String stringValue when effectiveTargetType == typeof(DateTimeOffset): + case string stringValue when effectiveTargetType == typeof(DateTimeOffset): if (!DateTimeOffset.TryParse(stringValue, CultureInfo.InvariantCulture, out var dateTimeOffsetResult)) { ThrowCouldNotConvertValueToTargetTypeException(stringValue, targetType); @@ -310,7 +310,7 @@ exception is ArgumentException or InvalidCastException or FormatException or Ove return dateTimeOffsetResult; - case String stringValue when effectiveTargetType == typeof(DateOnly): + case string stringValue when effectiveTargetType == typeof(DateOnly): if (!DateOnly.TryParse(stringValue, CultureInfo.InvariantCulture, out var dateOnlyResult)) { ThrowCouldNotConvertValueToTargetTypeException(stringValue, targetType); @@ -318,7 +318,7 @@ exception is ArgumentException or InvalidCastException or FormatException or Ove return dateOnlyResult; - case String stringValue when effectiveTargetType == typeof(TimeOnly): + case string stringValue when effectiveTargetType == typeof(TimeOnly): if (!TimeOnly.TryParse(stringValue, CultureInfo.InvariantCulture, out var timeOnlyResult)) { ThrowCouldNotConvertValueToTargetTypeException(stringValue, targetType); @@ -326,34 +326,34 @@ exception is ArgumentException or InvalidCastException or FormatException or Ove return timeOnlyResult; - case Guid guid when targetType == typeof(String): + case Guid guid when targetType == typeof(string): return guid.ToString("D"); - case Guid guid when targetType == typeof(Byte[]): + case Guid guid when targetType == typeof(byte[]): return guid.ToByteArray(); - case DateTime dateTime when targetType == typeof(String): + case DateTime dateTime when targetType == typeof(string): return dateTime.ToString("O", CultureInfo.InvariantCulture); case DateTime dateTime when effectiveTargetType == typeof(DateOnly): return DateOnly.FromDateTime(dateTime); - case TimeSpan timeSpan when targetType == typeof(String): + case TimeSpan timeSpan when targetType == typeof(string): return timeSpan.ToString("g", CultureInfo.InvariantCulture); case TimeSpan timeSpan when effectiveTargetType == typeof(TimeOnly): return TimeOnly.FromTimeSpan(timeSpan); - case Byte[] bytes when effectiveTargetType == typeof(Guid): + case byte[] bytes when effectiveTargetType == typeof(Guid): return new Guid(bytes); - case DateTimeOffset dateTimeOffset when targetType == typeof(String): + case DateTimeOffset dateTimeOffset when targetType == typeof(string): return dateTimeOffset.ToString("O", CultureInfo.InvariantCulture); - case DateOnly dateOnly when targetType == typeof(String): + case DateOnly dateOnly when targetType == typeof(string): return dateOnly.ToString("O", CultureInfo.InvariantCulture); - case TimeOnly timeOnly when targetType == typeof(String): + case TimeOnly timeOnly when targetType == typeof(string): return timeOnly.ToString("O", CultureInfo.InvariantCulture); default: @@ -389,7 +389,7 @@ exception is ArgumentException or InvalidCastException or FormatException or Ove /// if is a type that can be converted to an enum type or a type /// that an enum can be converted to; otherwise, . /// - private static Boolean IsSupportedEnumConversionType(Type type) => + private static bool IsSupportedEnumConversionType(Type type) => Type.GetTypeCode(type) is // Ordered by frequency of use: TypeCode.String or @@ -407,7 +407,7 @@ TypeCode.UInt32 or [MethodImpl(MethodImplOptions.NoInlining)] [DoesNotReturn] - private static void ThrowCouldNotConvertNonSingleCharStringToCharException(String stringValue, Type targetType) => + private static void ThrowCouldNotConvertNonSingleCharStringToCharException(string stringValue, Type targetType) => throw new InvalidCastException( $"Could not convert the string '{stringValue}' to the type {targetType}. The string must be exactly one " + "character long." @@ -416,7 +416,7 @@ private static void ThrowCouldNotConvertNonSingleCharStringToCharException(Strin [MethodImpl(MethodImplOptions.NoInlining)] [DoesNotReturn] private static void ThrowCouldNotConvertNullOrDbNullToNonNullableTargetTypeException( - Object? value, + object? value, Type targetType ) => throw new InvalidCastException( @@ -427,7 +427,7 @@ Type targetType [MethodImpl(MethodImplOptions.NoInlining)] [DoesNotReturn] private static void ThrowCouldNotConvertValueToTargetTypeException( - Object? value, + object? value, Type targetType, Exception innerException ) => @@ -440,7 +440,7 @@ Exception innerException [MethodImpl(MethodImplOptions.NoInlining)] [DoesNotReturn] private static void ThrowCouldNotConvertValueToTargetTypeException( - Object? value, + object? value, Type targetType ) => throw new InvalidCastException( @@ -449,238 +449,238 @@ Type targetType private static readonly HashSet<(Type SourceType, Type TargetType)> supportedConversions = [ - (typeof(Boolean), typeof(Boolean)), - (typeof(Boolean), typeof(Byte)), - (typeof(Boolean), typeof(Decimal)), - (typeof(Boolean), typeof(Double)), - (typeof(Boolean), typeof(Int16)), - (typeof(Boolean), typeof(Int32)), - (typeof(Boolean), typeof(Int64)), - (typeof(Boolean), typeof(SByte)), - (typeof(Boolean), typeof(Single)), - (typeof(Boolean), typeof(String)), - (typeof(Boolean), typeof(UInt16)), - (typeof(Boolean), typeof(UInt32)), - (typeof(Boolean), typeof(UInt64)), - - (typeof(Byte), typeof(Boolean)), - (typeof(Byte), typeof(Byte)), - (typeof(Byte), typeof(Char)), - (typeof(Byte), typeof(Decimal)), - (typeof(Byte), typeof(Double)), - (typeof(Byte), typeof(Int16)), - (typeof(Byte), typeof(Int32)), - (typeof(Byte), typeof(Int64)), - (typeof(Byte), typeof(SByte)), - (typeof(Byte), typeof(Single)), - (typeof(Byte), typeof(String)), - (typeof(Byte), typeof(UInt16)), - (typeof(Byte), typeof(UInt32)), - (typeof(Byte), typeof(UInt64)), - - (typeof(Byte[]), typeof(Guid)), - - (typeof(Char), typeof(Byte)), - (typeof(Char), typeof(Char)), - (typeof(Char), typeof(Int16)), - (typeof(Char), typeof(Int32)), - (typeof(Char), typeof(Int64)), - (typeof(Char), typeof(SByte)), - (typeof(Char), typeof(String)), - (typeof(Char), typeof(UInt16)), - (typeof(Char), typeof(UInt32)), - (typeof(Char), typeof(UInt64)), + (typeof(bool), typeof(bool)), + (typeof(bool), typeof(byte)), + (typeof(bool), typeof(decimal)), + (typeof(bool), typeof(double)), + (typeof(bool), typeof(short)), + (typeof(bool), typeof(int)), + (typeof(bool), typeof(long)), + (typeof(bool), typeof(sbyte)), + (typeof(bool), typeof(float)), + (typeof(bool), typeof(string)), + (typeof(bool), typeof(ushort)), + (typeof(bool), typeof(uint)), + (typeof(bool), typeof(ulong)), + + (typeof(byte), typeof(bool)), + (typeof(byte), typeof(byte)), + (typeof(byte), typeof(char)), + (typeof(byte), typeof(decimal)), + (typeof(byte), typeof(double)), + (typeof(byte), typeof(short)), + (typeof(byte), typeof(int)), + (typeof(byte), typeof(long)), + (typeof(byte), typeof(sbyte)), + (typeof(byte), typeof(float)), + (typeof(byte), typeof(string)), + (typeof(byte), typeof(ushort)), + (typeof(byte), typeof(uint)), + (typeof(byte), typeof(ulong)), + + (typeof(byte[]), typeof(Guid)), + + (typeof(char), typeof(byte)), + (typeof(char), typeof(char)), + (typeof(char), typeof(short)), + (typeof(char), typeof(int)), + (typeof(char), typeof(long)), + (typeof(char), typeof(sbyte)), + (typeof(char), typeof(string)), + (typeof(char), typeof(ushort)), + (typeof(char), typeof(uint)), + (typeof(char), typeof(ulong)), (typeof(DateOnly), typeof(DateOnly)), - (typeof(DateOnly), typeof(String)), + (typeof(DateOnly), typeof(string)), (typeof(DateTime), typeof(DateTime)), (typeof(DateTime), typeof(DateOnly)), - (typeof(DateTime), typeof(String)), + (typeof(DateTime), typeof(string)), (typeof(DateTimeOffset), typeof(DateTimeOffset)), - (typeof(DateTimeOffset), typeof(String)), - - (typeof(Decimal), typeof(Boolean)), - (typeof(Decimal), typeof(Byte)), - (typeof(Decimal), typeof(Decimal)), - (typeof(Decimal), typeof(Double)), - (typeof(Decimal), typeof(Int16)), - (typeof(Decimal), typeof(Int32)), - (typeof(Decimal), typeof(Int64)), - (typeof(Decimal), typeof(SByte)), - (typeof(Decimal), typeof(Single)), - (typeof(Decimal), typeof(String)), - (typeof(Decimal), typeof(UInt16)), - (typeof(Decimal), typeof(UInt32)), - (typeof(Decimal), typeof(UInt64)), - - (typeof(Double), typeof(Boolean)), - (typeof(Double), typeof(Byte)), - (typeof(Double), typeof(Decimal)), - (typeof(Double), typeof(Double)), - (typeof(Double), typeof(Int16)), - (typeof(Double), typeof(Int32)), - (typeof(Double), typeof(Int64)), - (typeof(Double), typeof(SByte)), - (typeof(Double), typeof(Single)), - (typeof(Double), typeof(String)), - (typeof(Double), typeof(UInt16)), - (typeof(Double), typeof(UInt32)), - (typeof(Double), typeof(UInt64)), - - (typeof(Guid), typeof(Byte[])), + (typeof(DateTimeOffset), typeof(string)), + + (typeof(decimal), typeof(bool)), + (typeof(decimal), typeof(byte)), + (typeof(decimal), typeof(decimal)), + (typeof(decimal), typeof(double)), + (typeof(decimal), typeof(short)), + (typeof(decimal), typeof(int)), + (typeof(decimal), typeof(long)), + (typeof(decimal), typeof(sbyte)), + (typeof(decimal), typeof(float)), + (typeof(decimal), typeof(string)), + (typeof(decimal), typeof(ushort)), + (typeof(decimal), typeof(uint)), + (typeof(decimal), typeof(ulong)), + + (typeof(double), typeof(bool)), + (typeof(double), typeof(byte)), + (typeof(double), typeof(decimal)), + (typeof(double), typeof(double)), + (typeof(double), typeof(short)), + (typeof(double), typeof(int)), + (typeof(double), typeof(long)), + (typeof(double), typeof(sbyte)), + (typeof(double), typeof(float)), + (typeof(double), typeof(string)), + (typeof(double), typeof(ushort)), + (typeof(double), typeof(uint)), + (typeof(double), typeof(ulong)), + + (typeof(Guid), typeof(byte[])), (typeof(Guid), typeof(Guid)), - (typeof(Guid), typeof(String)), - - (typeof(Int16), typeof(Boolean)), - (typeof(Int16), typeof(Byte)), - (typeof(Int16), typeof(Char)), - (typeof(Int16), typeof(Decimal)), - (typeof(Int16), typeof(Double)), - (typeof(Int16), typeof(Int16)), - (typeof(Int16), typeof(Int32)), - (typeof(Int16), typeof(Int64)), - (typeof(Int16), typeof(SByte)), - (typeof(Int16), typeof(Single)), - (typeof(Int16), typeof(String)), - (typeof(Int16), typeof(UInt16)), - (typeof(Int16), typeof(UInt32)), - (typeof(Int16), typeof(UInt64)), - - (typeof(Int32), typeof(Boolean)), - (typeof(Int32), typeof(Byte)), - (typeof(Int32), typeof(Char)), - (typeof(Int32), typeof(Decimal)), - (typeof(Int32), typeof(Double)), - (typeof(Int32), typeof(Int16)), - (typeof(Int32), typeof(Int32)), - (typeof(Int32), typeof(Int64)), - (typeof(Int32), typeof(SByte)), - (typeof(Int32), typeof(Single)), - (typeof(Int32), typeof(String)), - (typeof(Int32), typeof(UInt16)), - (typeof(Int32), typeof(UInt32)), - (typeof(Int32), typeof(UInt64)), - - (typeof(Int64), typeof(Boolean)), - (typeof(Int64), typeof(Byte)), - (typeof(Int64), typeof(Char)), - (typeof(Int64), typeof(Decimal)), - (typeof(Int64), typeof(Double)), - (typeof(Int64), typeof(Int16)), - (typeof(Int64), typeof(Int32)), - (typeof(Int64), typeof(Int64)), - (typeof(Int64), typeof(SByte)), - (typeof(Int64), typeof(Single)), - (typeof(Int64), typeof(String)), - (typeof(Int64), typeof(UInt16)), - (typeof(Int64), typeof(UInt32)), - (typeof(Int64), typeof(UInt64)), + (typeof(Guid), typeof(string)), + + (typeof(short), typeof(bool)), + (typeof(short), typeof(byte)), + (typeof(short), typeof(char)), + (typeof(short), typeof(decimal)), + (typeof(short), typeof(double)), + (typeof(short), typeof(short)), + (typeof(short), typeof(int)), + (typeof(short), typeof(long)), + (typeof(short), typeof(sbyte)), + (typeof(short), typeof(float)), + (typeof(short), typeof(string)), + (typeof(short), typeof(ushort)), + (typeof(short), typeof(uint)), + (typeof(short), typeof(ulong)), + + (typeof(int), typeof(bool)), + (typeof(int), typeof(byte)), + (typeof(int), typeof(char)), + (typeof(int), typeof(decimal)), + (typeof(int), typeof(double)), + (typeof(int), typeof(short)), + (typeof(int), typeof(int)), + (typeof(int), typeof(long)), + (typeof(int), typeof(sbyte)), + (typeof(int), typeof(float)), + (typeof(int), typeof(string)), + (typeof(int), typeof(ushort)), + (typeof(int), typeof(uint)), + (typeof(int), typeof(ulong)), + + (typeof(long), typeof(bool)), + (typeof(long), typeof(byte)), + (typeof(long), typeof(char)), + (typeof(long), typeof(decimal)), + (typeof(long), typeof(double)), + (typeof(long), typeof(short)), + (typeof(long), typeof(int)), + (typeof(long), typeof(long)), + (typeof(long), typeof(sbyte)), + (typeof(long), typeof(float)), + (typeof(long), typeof(string)), + (typeof(long), typeof(ushort)), + (typeof(long), typeof(uint)), + (typeof(long), typeof(ulong)), (typeof(IntPtr), typeof(IntPtr)), - (typeof(SByte), typeof(Boolean)), - (typeof(SByte), typeof(Byte)), - (typeof(SByte), typeof(Char)), - (typeof(SByte), typeof(Decimal)), - (typeof(SByte), typeof(Double)), - (typeof(SByte), typeof(Int16)), - (typeof(SByte), typeof(Int32)), - (typeof(SByte), typeof(Int64)), - (typeof(SByte), typeof(SByte)), - (typeof(SByte), typeof(Single)), - (typeof(SByte), typeof(String)), - (typeof(SByte), typeof(UInt16)), - (typeof(SByte), typeof(UInt32)), - (typeof(SByte), typeof(UInt64)), - - (typeof(Single), typeof(Boolean)), - (typeof(Single), typeof(Byte)), - (typeof(Single), typeof(Decimal)), - (typeof(Single), typeof(Double)), - (typeof(Single), typeof(Int16)), - (typeof(Single), typeof(Int32)), - (typeof(Single), typeof(Int64)), - (typeof(Single), typeof(SByte)), - (typeof(Single), typeof(Single)), - (typeof(Single), typeof(String)), - (typeof(Single), typeof(UInt16)), - (typeof(Single), typeof(UInt32)), - (typeof(Single), typeof(UInt64)), - - (typeof(String), typeof(Boolean)), - (typeof(String), typeof(Byte)), - (typeof(String), typeof(Char)), - (typeof(String), typeof(DateTime)), - (typeof(String), typeof(DateTimeOffset)), - (typeof(String), typeof(DateOnly)), - (typeof(String), typeof(Decimal)), - (typeof(String), typeof(Double)), - (typeof(String), typeof(Guid)), - (typeof(String), typeof(Int16)), - (typeof(String), typeof(Int32)), - (typeof(String), typeof(Int64)), - (typeof(String), typeof(SByte)), - (typeof(String), typeof(Single)), - (typeof(String), typeof(String)), - (typeof(String), typeof(UInt16)), - (typeof(String), typeof(UInt32)), - (typeof(String), typeof(UInt64)), - (typeof(String), typeof(TimeSpan)), - (typeof(String), typeof(TimeOnly)), + (typeof(sbyte), typeof(bool)), + (typeof(sbyte), typeof(byte)), + (typeof(sbyte), typeof(char)), + (typeof(sbyte), typeof(decimal)), + (typeof(sbyte), typeof(double)), + (typeof(sbyte), typeof(short)), + (typeof(sbyte), typeof(int)), + (typeof(sbyte), typeof(long)), + (typeof(sbyte), typeof(sbyte)), + (typeof(sbyte), typeof(float)), + (typeof(sbyte), typeof(string)), + (typeof(sbyte), typeof(ushort)), + (typeof(sbyte), typeof(uint)), + (typeof(sbyte), typeof(ulong)), + + (typeof(float), typeof(bool)), + (typeof(float), typeof(byte)), + (typeof(float), typeof(decimal)), + (typeof(float), typeof(double)), + (typeof(float), typeof(short)), + (typeof(float), typeof(int)), + (typeof(float), typeof(long)), + (typeof(float), typeof(sbyte)), + (typeof(float), typeof(float)), + (typeof(float), typeof(string)), + (typeof(float), typeof(ushort)), + (typeof(float), typeof(uint)), + (typeof(float), typeof(ulong)), + + (typeof(string), typeof(bool)), + (typeof(string), typeof(byte)), + (typeof(string), typeof(char)), + (typeof(string), typeof(DateTime)), + (typeof(string), typeof(DateTimeOffset)), + (typeof(string), typeof(DateOnly)), + (typeof(string), typeof(decimal)), + (typeof(string), typeof(double)), + (typeof(string), typeof(Guid)), + (typeof(string), typeof(short)), + (typeof(string), typeof(int)), + (typeof(string), typeof(long)), + (typeof(string), typeof(sbyte)), + (typeof(string), typeof(float)), + (typeof(string), typeof(string)), + (typeof(string), typeof(ushort)), + (typeof(string), typeof(uint)), + (typeof(string), typeof(ulong)), + (typeof(string), typeof(TimeSpan)), + (typeof(string), typeof(TimeOnly)), (typeof(TimeOnly), typeof(TimeOnly)), - (typeof(TimeOnly), typeof(String)), + (typeof(TimeOnly), typeof(string)), (typeof(TimeSpan), typeof(TimeOnly)), (typeof(TimeSpan), typeof(TimeSpan)), - (typeof(TimeSpan), typeof(String)), - - (typeof(UInt16), typeof(Boolean)), - (typeof(UInt16), typeof(Byte)), - (typeof(UInt16), typeof(Char)), - (typeof(UInt16), typeof(Decimal)), - (typeof(UInt16), typeof(Double)), - (typeof(UInt16), typeof(Int16)), - (typeof(UInt16), typeof(Int32)), - (typeof(UInt16), typeof(Int64)), - (typeof(UInt16), typeof(SByte)), - (typeof(UInt16), typeof(Single)), - (typeof(UInt16), typeof(String)), - (typeof(UInt16), typeof(UInt16)), - (typeof(UInt16), typeof(UInt32)), - (typeof(UInt16), typeof(UInt64)), - - (typeof(UInt32), typeof(Boolean)), - (typeof(UInt32), typeof(Byte)), - (typeof(UInt32), typeof(Char)), - (typeof(UInt32), typeof(Decimal)), - (typeof(UInt32), typeof(Double)), - (typeof(UInt32), typeof(Int16)), - (typeof(UInt32), typeof(Int32)), - (typeof(UInt32), typeof(Int64)), - (typeof(UInt32), typeof(SByte)), - (typeof(UInt32), typeof(Single)), - (typeof(UInt32), typeof(String)), - (typeof(UInt32), typeof(UInt16)), - (typeof(UInt32), typeof(UInt32)), - (typeof(UInt32), typeof(UInt64)), - - (typeof(UInt64), typeof(Boolean)), - (typeof(UInt64), typeof(Byte)), - (typeof(UInt64), typeof(Char)), - (typeof(UInt64), typeof(Decimal)), - (typeof(UInt64), typeof(Double)), - (typeof(UInt64), typeof(Int16)), - (typeof(UInt64), typeof(Int32)), - (typeof(UInt64), typeof(Int64)), - (typeof(UInt64), typeof(SByte)), - (typeof(UInt64), typeof(Single)), - (typeof(UInt64), typeof(String)), - (typeof(UInt64), typeof(UInt16)), - (typeof(UInt64), typeof(UInt32)), - (typeof(UInt64), typeof(UInt64)), + (typeof(TimeSpan), typeof(string)), + + (typeof(ushort), typeof(bool)), + (typeof(ushort), typeof(byte)), + (typeof(ushort), typeof(char)), + (typeof(ushort), typeof(decimal)), + (typeof(ushort), typeof(double)), + (typeof(ushort), typeof(short)), + (typeof(ushort), typeof(int)), + (typeof(ushort), typeof(long)), + (typeof(ushort), typeof(sbyte)), + (typeof(ushort), typeof(float)), + (typeof(ushort), typeof(string)), + (typeof(ushort), typeof(ushort)), + (typeof(ushort), typeof(uint)), + (typeof(ushort), typeof(ulong)), + + (typeof(uint), typeof(bool)), + (typeof(uint), typeof(byte)), + (typeof(uint), typeof(char)), + (typeof(uint), typeof(decimal)), + (typeof(uint), typeof(double)), + (typeof(uint), typeof(short)), + (typeof(uint), typeof(int)), + (typeof(uint), typeof(long)), + (typeof(uint), typeof(sbyte)), + (typeof(uint), typeof(float)), + (typeof(uint), typeof(string)), + (typeof(uint), typeof(ushort)), + (typeof(uint), typeof(uint)), + (typeof(uint), typeof(ulong)), + + (typeof(ulong), typeof(bool)), + (typeof(ulong), typeof(byte)), + (typeof(ulong), typeof(char)), + (typeof(ulong), typeof(decimal)), + (typeof(ulong), typeof(double)), + (typeof(ulong), typeof(short)), + (typeof(ulong), typeof(int)), + (typeof(ulong), typeof(long)), + (typeof(ulong), typeof(sbyte)), + (typeof(ulong), typeof(float)), + (typeof(ulong), typeof(string)), + (typeof(ulong), typeof(ushort)), + (typeof(ulong), typeof(uint)), + (typeof(ulong), typeof(ulong)), (typeof(UIntPtr), typeof(UIntPtr)) ]; diff --git a/src/DbConnectionPlus/DatabaseAdapters/Constants.cs b/src/DbConnectionPlus/DatabaseAdapters/Constants.cs index 4b796ec..0e24630 100644 --- a/src/DbConnectionPlus/DatabaseAdapters/Constants.cs +++ b/src/DbConnectionPlus/DatabaseAdapters/Constants.cs @@ -11,10 +11,10 @@ public static class Constants /// /// The string to use to indent parts of SQL statements. /// - public const String Indent = " "; + public const string Indent = " "; /// /// The name to use for the single column of single column temporary tables. /// - public const String SingleColumnTemporaryTableColumnName = "Value"; + public const string SingleColumnTemporaryTableColumnName = "Value"; } diff --git a/src/DbConnectionPlus/DatabaseAdapters/IDatabaseAdapter.cs b/src/DbConnectionPlus/DatabaseAdapters/IDatabaseAdapter.cs index f62cb9d..20758e1 100644 --- a/src/DbConnectionPlus/DatabaseAdapters/IDatabaseAdapter.cs +++ b/src/DbConnectionPlus/DatabaseAdapters/IDatabaseAdapter.cs @@ -30,7 +30,7 @@ public interface IDatabaseAdapter /// The parameter to bind to. /// The value to bind to . /// is . - public void BindParameterValue(DbParameter parameter, Object? value); + public void BindParameterValue(DbParameter parameter, object? value); /// /// Returns with the appropriate prefix @@ -41,7 +41,7 @@ public interface IDatabaseAdapter /// formatted with the appropriate prefix, suitable for inclusion in SQL /// statements. /// - public String FormatParameterName(String parameterName); + public string FormatParameterName(string parameterName); /// /// Gets the corresponding database specific data type for the type . @@ -67,7 +67,7 @@ public interface IDatabaseAdapter /// /// /// - public String GetDataType(Type type, EnumSerializationMode enumSerializationMode); + public string GetDataType(Type type, EnumSerializationMode enumSerializationMode); /// /// Returns properly quoted for use in SQL statements. @@ -76,7 +76,7 @@ public interface IDatabaseAdapter /// /// A string containing the quoted version of , suitable for use in SQL statements. /// - public String QuoteIdentifier(String identifier); + public string QuoteIdentifier(string identifier); /// /// Returns the specified name of a temporary table properly quoted for use in SQL statements. @@ -86,7 +86,7 @@ public interface IDatabaseAdapter /// /// A string containing the quoted version of , suitable for use in SQL statements. /// - public String QuoteTemporaryTableName(String tableName, DbConnection connection); + public string QuoteTemporaryTableName(string tableName, DbConnection connection); /// /// Determines whether the database system this adapter supports has support for (local/session scoped) temporary @@ -107,7 +107,7 @@ public interface IDatabaseAdapter /// from the property. /// /// - public Boolean SupportsTemporaryTables(DbConnection connection); + public bool SupportsTemporaryTables(DbConnection connection); /// /// Determines whether was thrown because an SQL statement was cancelled via @@ -120,7 +120,7 @@ public interface IDatabaseAdapter /// ; otherwise, . /// /// is . - public Boolean WasSqlStatementCancelledByCancellationToken( + public bool WasSqlStatementCancelledByCancellationToken( Exception exception, CancellationToken cancellationToken ); diff --git a/src/DbConnectionPlus/DatabaseAdapters/IEntityManipulator.cs b/src/DbConnectionPlus/DatabaseAdapters/IEntityManipulator.cs index c542531..7e9dea0 100644 --- a/src/DbConnectionPlus/DatabaseAdapters/IEntityManipulator.cs +++ b/src/DbConnectionPlus/DatabaseAdapters/IEntityManipulator.cs @@ -56,7 +56,7 @@ public interface IEntityManipulator /// Use or to configure key properties. /// /// - public Int32 DeleteEntities< + public int DeleteEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -114,7 +114,7 @@ CancellationToken cancellationToken /// Use or to configure key properties. /// /// - public Task DeleteEntitiesAsync< + public Task DeleteEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -168,7 +168,7 @@ CancellationToken cancellationToken /// Use or to configure key properties. /// /// - public Int32 DeleteEntity< + public int DeleteEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -226,7 +226,7 @@ CancellationToken cancellationToken /// Use or to configure key properties. /// /// - public Task DeleteEntityAsync< + public Task DeleteEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -288,7 +288,7 @@ CancellationToken cancellationToken /// properties are updated accordingly. /// /// - public Int32 InsertEntities< + public int InsertEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -353,7 +353,7 @@ CancellationToken cancellationToken /// properties are updated accordingly. /// /// - public Task InsertEntitiesAsync< + public Task InsertEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -414,7 +414,7 @@ CancellationToken cancellationToken /// properties are updated accordingly. /// /// - public Int32 InsertEntity< + public int InsertEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -479,7 +479,7 @@ CancellationToken cancellationToken /// properties are updated accordingly. /// /// - public Task InsertEntityAsync< + public Task InsertEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -552,7 +552,7 @@ CancellationToken cancellationToken /// properties are updated accordingly. /// /// - public Int32 UpdateEntities< + public int UpdateEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -630,7 +630,7 @@ CancellationToken cancellationToken /// properties are updated accordingly. /// /// - public Task UpdateEntitiesAsync< + public Task UpdateEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -703,7 +703,7 @@ CancellationToken cancellationToken /// properties are updated accordingly. /// /// - public Int32 UpdateEntity< + public int UpdateEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, @@ -780,7 +780,7 @@ CancellationToken cancellationToken /// properties are updated accordingly. /// /// - public Task UpdateEntityAsync< + public Task UpdateEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbConnection connection, diff --git a/src/DbConnectionPlus/DatabaseAdapters/ITemporaryTableBuilder.cs b/src/DbConnectionPlus/DatabaseAdapters/ITemporaryTableBuilder.cs index 2b366a4..b5bbead 100644 --- a/src/DbConnectionPlus/DatabaseAdapters/ITemporaryTableBuilder.cs +++ b/src/DbConnectionPlus/DatabaseAdapters/ITemporaryTableBuilder.cs @@ -64,7 +64,7 @@ public interface ITemporaryTableBuilder /// /// /// If the type is a scalar type - /// (e.g. , , , and so on), + /// (e.g. , , , and so on), /// a single-column table will be built with a column named "Value" with a data type that matches the /// type . /// @@ -80,7 +80,7 @@ public interface ITemporaryTableBuilder public TemporaryTableDisposer BuildTemporaryTable( DbConnection connection, DbTransaction? transaction, - String name, + string name, IEnumerable values, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, @@ -145,7 +145,7 @@ public TemporaryTableDisposer BuildTemporaryTable( /// /// /// If the type is a scalar type - /// (e.g. , , , and so on), + /// (e.g. , , , and so on), /// a single-column table will be built with a column named "Value" with a data type that matches /// the type . /// @@ -161,7 +161,7 @@ public TemporaryTableDisposer BuildTemporaryTable( public Task BuildTemporaryTableAsync( DbConnection connection, DbTransaction? transaction, - String name, + string name, IEnumerable values, [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, diff --git a/src/DbConnectionPlus/DatabaseAdapters/TemporaryTableDisposer.cs b/src/DbConnectionPlus/DatabaseAdapters/TemporaryTableDisposer.cs index e56f1c6..6a32a63 100644 --- a/src/DbConnectionPlus/DatabaseAdapters/TemporaryTableDisposer.cs +++ b/src/DbConnectionPlus/DatabaseAdapters/TemporaryTableDisposer.cs @@ -69,5 +69,5 @@ public ValueTask DisposeAsync() private readonly Func dropTableAsyncFunction; private readonly Action dropTableFunction; - private Boolean isDisposed; + private bool isDisposed; } diff --git a/src/DbConnectionPlus/DbCommands/DbCommandBuilder.cs b/src/DbConnectionPlus/DbCommands/DbCommandBuilder.cs index 28d1616..b41d422 100644 --- a/src/DbConnectionPlus/DbCommands/DbCommandBuilder.cs +++ b/src/DbConnectionPlus/DbCommands/DbCommandBuilder.cs @@ -185,9 +185,9 @@ private static (DbCommand, CancellationTokenRegistration) BuildDbCommandCore( CancellationToken cancellationToken = default ) { - using var codeBuilder = new ValueStringBuilder(stackalloc Char[512]); + using var codeBuilder = new ValueStringBuilder(stackalloc char[512]); - var parameterNameOccurrences = new Dictionary( + var parameterNameOccurrences = new Dictionary( statement.Fragments.Count, StringComparer.OrdinalIgnoreCase ); @@ -201,7 +201,7 @@ private static (DbCommand, CancellationTokenRegistration) BuildDbCommandCore( if (commandTimeout is not null) { - command.CommandTimeout = (Int32)commandTimeout.Value.TotalSeconds; + command.CommandTimeout = (int)commandTimeout.Value.TotalSeconds; } var dbParameters = command.Parameters; diff --git a/src/DbConnectionPlus/DbCommands/DbCommandDisposer.cs b/src/DbConnectionPlus/DbCommands/DbCommandDisposer.cs index 976cc9e..03db21a 100644 --- a/src/DbConnectionPlus/DbCommands/DbCommandDisposer.cs +++ b/src/DbConnectionPlus/DbCommands/DbCommandDisposer.cs @@ -95,5 +95,5 @@ public async ValueTask DisposeAsync() private readonly DbCommand command; private readonly TemporaryTableDisposer[] temporaryTableDisposers; - private Boolean isDisposed; + private bool isDisposed; } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.Configuration.cs b/src/DbConnectionPlus/DbConnectionExtensions.Configuration.cs index 34dc38b..1885b51 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.Configuration.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.Configuration.cs @@ -47,5 +47,5 @@ IReadOnlyList temporaryTables ) => DbConnectionPlusConfiguration.Instance.InterceptDbCommand?.Invoke(command, temporaryTables); - private static readonly Object configurationLockObject = new(); + private static readonly object configurationLockObject = new(); } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.DeleteEntities.cs b/src/DbConnectionPlus/DbConnectionExtensions.DeleteEntities.cs index 1c116e3..ad4331a 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.DeleteEntities.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.DeleteEntities.cs @@ -69,7 +69,7 @@ public static partial class DbConnectionExtensions /// connection.DeleteEntities(products.Where(a => a.IsDiscontinued)); /// /// - public static Int32 DeleteEntities< + public static int DeleteEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( this DbConnection connection, @@ -154,7 +154,7 @@ public static Int32 DeleteEntities< /// await connection.DeleteEntitiesAsync(products.Where(a => a.IsDiscontinued)); /// /// - public static Task DeleteEntitiesAsync< + public static Task DeleteEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( this DbConnection connection, diff --git a/src/DbConnectionPlus/DbConnectionExtensions.DeleteEntity.cs b/src/DbConnectionPlus/DbConnectionExtensions.DeleteEntity.cs index f4036a0..af10cdb 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.DeleteEntity.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.DeleteEntity.cs @@ -72,7 +72,7 @@ public static partial class DbConnectionExtensions /// } /// /// - public static Int32 DeleteEntity< + public static int DeleteEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( this DbConnection connection, @@ -160,7 +160,7 @@ public static Int32 DeleteEntity< /// } /// /// - public static Task DeleteEntityAsync< + public static Task DeleteEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( this DbConnection connection, diff --git a/src/DbConnectionPlus/DbConnectionExtensions.ExecuteNonQuery.cs b/src/DbConnectionPlus/DbConnectionExtensions.ExecuteNonQuery.cs index 9b99813..fa4e768 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.ExecuteNonQuery.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.ExecuteNonQuery.cs @@ -40,7 +40,7 @@ public static partial class DbConnectionExtensions /// } /// /// - public static Int32 ExecuteNonQuery( + public static int ExecuteNonQuery( this DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, @@ -112,7 +112,7 @@ public static Int32 ExecuteNonQuery( /// } /// /// - public static async Task ExecuteNonQueryAsync( + public static async Task ExecuteNonQueryAsync( this DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, diff --git a/src/DbConnectionPlus/DbConnectionExtensions.ExecuteScalar.cs b/src/DbConnectionPlus/DbConnectionExtensions.ExecuteScalar.cs index 7a76954..424b1bc 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.ExecuteScalar.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.ExecuteScalar.cs @@ -205,7 +205,7 @@ public static async Task ExecuteScalarAsync( /// /// could not be converted to the type . /// - private static TTarget ConvertValueForExecuteScalar(Object? value) + private static TTarget ConvertValueForExecuteScalar(object? value) { try { diff --git a/src/DbConnectionPlus/DbConnectionExtensions.Exists.cs b/src/DbConnectionPlus/DbConnectionExtensions.Exists.cs index 7b729d8..34db0ea 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.Exists.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.Exists.cs @@ -12,7 +12,7 @@ namespace RentADeveloper.DbConnectionPlus; public static partial class DbConnectionExtensions { /// - /// Executes the specified SQL statement and returns a value indicating whether the result + /// Executes the specified SQL statement and returns a value indicating whether the result /// set returned by the statement contains at least one row. /// This method is intended to check for the existence of rows matching certain criteria, e.g. checking whether a /// Product with a specific Id exists. @@ -47,7 +47,7 @@ public static partial class DbConnectionExtensions /// ]]> /// /// - public static Boolean Exists( + public static bool Exists( this DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, @@ -88,7 +88,7 @@ public static Boolean Exists( } /// - /// Asynchronously executes the specified SQL statement and returns a value indicating + /// Asynchronously executes the specified SQL statement and returns a value indicating /// whether the result set returned by the statement contains at least one row. /// This method is intended to check for the existence of rows matching certain criteria, e.g. checking whether a /// Product with a specific Id exists. @@ -125,7 +125,7 @@ public static Boolean Exists( /// ]]> /// /// - public static async Task ExistsAsync( + public static async Task ExistsAsync( this DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, diff --git a/src/DbConnectionPlus/DbConnectionExtensions.InsertEntities.cs b/src/DbConnectionPlus/DbConnectionExtensions.InsertEntities.cs index 128ba03..89c63e5 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.InsertEntities.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.InsertEntities.cs @@ -80,7 +80,7 @@ public static partial class DbConnectionExtensions /// connection.InsertEntities(newProducts); /// /// - public static Int32 InsertEntities< + public static int InsertEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( this DbConnection connection, @@ -176,7 +176,7 @@ public static Int32 InsertEntities< /// await connection.InsertEntitiesAsync(newProducts); /// /// - public static Task InsertEntitiesAsync< + public static Task InsertEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( this DbConnection connection, diff --git a/src/DbConnectionPlus/DbConnectionExtensions.InsertEntity.cs b/src/DbConnectionPlus/DbConnectionExtensions.InsertEntity.cs index 0c5a95a..38f2a01 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.InsertEntity.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.InsertEntity.cs @@ -80,7 +80,7 @@ public static partial class DbConnectionExtensions /// connection.InsertEntity(newProduct); /// /// - public static Int32 InsertEntity< + public static int InsertEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( this DbConnection connection, @@ -176,7 +176,7 @@ public static Int32 InsertEntity< /// await connection.InsertEntityAsync(newProduct); /// /// - public static Task InsertEntityAsync< + public static Task InsertEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( this DbConnection connection, diff --git a/src/DbConnectionPlus/DbConnectionExtensions.Parameter.cs b/src/DbConnectionPlus/DbConnectionExtensions.Parameter.cs index 57d9dd7..49ff748 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.Parameter.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.Parameter.cs @@ -66,12 +66,12 @@ public static partial class DbConnectionExtensions /// /// public static InterpolatedParameter Parameter( - Object? parameterValue, + object? parameterValue, [CallerArgumentExpression(nameof(parameterValue))] - String? parameterValueExpression = null + string? parameterValueExpression = null ) { - String? inferredParameterName = null; + string? inferredParameterName = null; if (parameterValueExpression?.Length > 0) { @@ -92,5 +92,5 @@ public static InterpolatedParameter Parameter( /// /// The maximum length for inferred parameter names. This length is supported by all major database systems. /// - private const Int32 MaximumParameterNameLength = 60; + private const int MaximumParameterNameLength = 60; } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.QueryFirstOfT.cs b/src/DbConnectionPlus/DbConnectionExtensions.QueryFirstOfT.cs index bac7c9c..311887b 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.QueryFirstOfT.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.QueryFirstOfT.cs @@ -95,7 +95,7 @@ public static partial class DbConnectionExtensions /// /// /// A built-in .NET type or a nullable built-in .NET type like or - /// . + /// . /// /// /// In this case only the first column of the result set will be read and converted to the type @@ -344,7 +344,7 @@ public static T QueryFirst< /// /// /// A built-in .NET type or a nullable built-in .NET type like or - /// . + /// . /// /// /// In this case only the first column of the result set will be read and converted to the type diff --git a/src/DbConnectionPlus/DbConnectionExtensions.QueryFirstOrDefaultOfT.cs b/src/DbConnectionPlus/DbConnectionExtensions.QueryFirstOrDefaultOfT.cs index f34f58d..3f11f57 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.QueryFirstOrDefaultOfT.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.QueryFirstOrDefaultOfT.cs @@ -95,7 +95,7 @@ public static partial class DbConnectionExtensions /// /// /// A built-in .NET type or a nullable built-in .NET type like or - /// . + /// . /// /// /// In this case only the first column of the result set will be read and converted to the type @@ -346,7 +346,7 @@ public static T? QueryFirstOrDefault< /// /// /// A built-in .NET type or a nullable built-in .NET type like or - /// . + /// . /// /// /// In this case only the first column of the result set will be read and converted to the type diff --git a/src/DbConnectionPlus/DbConnectionExtensions.QueryOfT.cs b/src/DbConnectionPlus/DbConnectionExtensions.QueryOfT.cs index 03d04c7..259046a 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.QueryOfT.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.QueryOfT.cs @@ -92,7 +92,7 @@ public static partial class DbConnectionExtensions /// /// /// A built-in .NET type or a nullable built-in .NET type like or - /// . + /// . /// /// /// In this case only the first column of the result set will be read and converted to the type @@ -356,7 +356,7 @@ public static IEnumerable Query< /// /// /// A built-in .NET type or a nullable built-in .NET type like or - /// . + /// . /// /// /// In this case only the first column of the result set will be read and converted to the type @@ -555,7 +555,7 @@ public static async IAsyncEnumerable QueryAsync< /// /// could not be converted to the type . /// - private static TTarget ConvertValueForQuery(Object? value) + private static TTarget ConvertValueForQuery(object? value) { try { diff --git a/src/DbConnectionPlus/DbConnectionExtensions.QuerySingleOfT.cs b/src/DbConnectionPlus/DbConnectionExtensions.QuerySingleOfT.cs index 8da0827..eba001c 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.QuerySingleOfT.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.QuerySingleOfT.cs @@ -108,7 +108,7 @@ public static partial class DbConnectionExtensions /// /// /// A built-in .NET type or a nullable built-in .NET type like or - /// . + /// . /// /// /// In this case only the first column of the result set will be read and converted to the type @@ -380,7 +380,7 @@ public static T QuerySingle< /// /// /// A built-in .NET type or a nullable built-in .NET type like or - /// . + /// . /// /// /// In this case only the first column of the result set will be read and converted to the type diff --git a/src/DbConnectionPlus/DbConnectionExtensions.QuerySingleOrDefaultOfT.cs b/src/DbConnectionPlus/DbConnectionExtensions.QuerySingleOrDefaultOfT.cs index d708320..c28c5df 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.QuerySingleOrDefaultOfT.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.QuerySingleOrDefaultOfT.cs @@ -96,7 +96,7 @@ public static partial class DbConnectionExtensions /// /// /// A built-in .NET type or a nullable built-in .NET type like or - /// . + /// . /// /// /// In this case only the first column of the result set will be read and converted to the type @@ -355,7 +355,7 @@ public static T? QuerySingleOrDefault< /// /// /// A built-in .NET type or a nullable built-in .NET type like or - /// . + /// . /// /// /// In this case only the first column of the result set will be read and converted to the type diff --git a/src/DbConnectionPlus/DbConnectionExtensions.TemporaryTable.cs b/src/DbConnectionPlus/DbConnectionExtensions.TemporaryTable.cs index e040a6c..8ec49ba 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.TemporaryTable.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.TemporaryTable.cs @@ -32,7 +32,7 @@ public static partial class DbConnectionExtensions /// An instance of indicating that the sequence /// should be passed as a temporary table to an SQL statement. /// - /// is the type . + /// is the type . /// is . /// /// To use this method import with a using directive with the static modifier: @@ -40,7 +40,7 @@ public static partial class DbConnectionExtensions /// using static RentADeveloper.DbConnectionPlus.DbConnectionExtensions; /// /// - /// You can pass a sequence of scalar values (e.g. , , + /// You can pass a sequence of scalar values (e.g. , , /// , and so on) or a sequence of complex objects. /// /// @@ -137,19 +137,19 @@ public static InterpolatedTemporaryTable TemporaryTable< >( IEnumerable values, [CallerArgumentExpression(nameof(values))] - String? valuesExpression = null + string? valuesExpression = null ) { ArgumentNullException.ThrowIfNull(values); - if (typeof(T) == typeof(Object)) + if (typeof(T) == typeof(object)) { - throw new ArgumentException($"The type parameter T cannot be the type {typeof(Object)}."); + throw new ArgumentException($"The type parameter T cannot be the type {typeof(object)}."); } - String? temporaryTableName = null; + string? temporaryTableName = null; - if (!String.IsNullOrWhiteSpace(valuesExpression)) + if (!string.IsNullOrWhiteSpace(valuesExpression)) { var nameFromCallerArgumentExpression = NameHelper.CreateNameFromCallerArgumentExpression( valuesExpression, @@ -158,13 +158,13 @@ public static InterpolatedTemporaryTable TemporaryTable< 27 ); - if (!String.IsNullOrWhiteSpace(nameFromCallerArgumentExpression)) + if (!string.IsNullOrWhiteSpace(nameFromCallerArgumentExpression)) { temporaryTableName = nameFromCallerArgumentExpression + "_" + Guid.NewGuid().ToString("N"); } } - if (String.IsNullOrWhiteSpace(temporaryTableName)) + if (string.IsNullOrWhiteSpace(temporaryTableName)) { temporaryTableName = "Values_" + Guid.NewGuid().ToString("N"); } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.UpdateEntities.cs b/src/DbConnectionPlus/DbConnectionExtensions.UpdateEntities.cs index 99c811f..176458c 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.UpdateEntities.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.UpdateEntities.cs @@ -105,7 +105,7 @@ public static partial class DbConnectionExtensions /// ]]> /// /// - public static Int32 UpdateEntities< + public static int UpdateEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( this DbConnection connection, @@ -226,7 +226,7 @@ public static Int32 UpdateEntities< /// ]]> /// /// - public static Task UpdateEntitiesAsync< + public static Task UpdateEntitiesAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( this DbConnection connection, diff --git a/src/DbConnectionPlus/DbConnectionExtensions.UpdateEntity.cs b/src/DbConnectionPlus/DbConnectionExtensions.UpdateEntity.cs index 1b85937..227bcd8 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.UpdateEntity.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.UpdateEntity.cs @@ -96,7 +96,7 @@ public static partial class DbConnectionExtensions /// ]]> /// /// - public static Int32 UpdateEntity< + public static int UpdateEntity< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( this DbConnection connection, @@ -207,7 +207,7 @@ public static Int32 UpdateEntity< /// ]]> /// /// - public static Task UpdateEntityAsync< + public static Task UpdateEntityAsync< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( this DbConnection connection, diff --git a/src/DbConnectionPlus/Dynamic/DataRow.cs b/src/DbConnectionPlus/Dynamic/DataRow.cs index bb203b5..f95828b 100644 --- a/src/DbConnectionPlus/Dynamic/DataRow.cs +++ b/src/DbConnectionPlus/Dynamic/DataRow.cs @@ -40,7 +40,7 @@ namespace RentADeveloper.DbConnectionPlus.Dynamic; /// /// #pragma warning disable CA1710 -public class DataRow : IDictionary, IDynamicMetaObjectProvider +public class DataRow : IDictionary, IDynamicMetaObjectProvider #pragma warning restore CA1710 { /// @@ -50,34 +50,34 @@ public class DataRow : IDictionary, IDynamicMetaObjectProvider /// The columns of the data row. /// The keys are expected to be the column names, and the values are expected to be the corresponding column values. /// - public DataRow(IDictionary columns) => + public DataRow(IDictionary columns) => this.columns = columns; /// - public Int32 Count => this.columns.Count; + public int Count => this.columns.Count; /// - public Boolean IsReadOnly => this.columns.IsReadOnly; + public bool IsReadOnly => this.columns.IsReadOnly; /// - public Object? this[String key] + public object? this[string key] { get => this.columns[key]; set => this.columns[key] = value; } /// - public ICollection Keys => this.columns.Keys; + public ICollection Keys => this.columns.Keys; /// - public ICollection Values => this.columns.Values; + public ICollection Values => this.columns.Values; /// - public void Add(KeyValuePair item) => + public void Add(KeyValuePair item) => this.columns.Add(item); /// - public void Add(String key, Object? value) => + public void Add(string key, object? value) => this.columns.Add(key, value); /// @@ -85,31 +85,31 @@ public void Clear() => this.columns.Clear(); /// - public Boolean Contains(KeyValuePair item) => + public bool Contains(KeyValuePair item) => this.columns.Contains(item); /// - public Boolean ContainsKey(String key) => + public bool ContainsKey(string key) => this.columns.ContainsKey(key); /// - public void CopyTo(KeyValuePair[] array, Int32 arrayIndex) => + public void CopyTo(KeyValuePair[] array, int arrayIndex) => this.columns.CopyTo(array, arrayIndex); /// - public IEnumerator> GetEnumerator() => + public IEnumerator> GetEnumerator() => this.columns.GetEnumerator(); /// - public Boolean Remove(KeyValuePair item) => + public bool Remove(KeyValuePair item) => this.columns.Remove(item); /// - public Boolean Remove(String key) => + public bool Remove(string key) => this.columns.Remove(key); /// - public Boolean TryGetValue(String key, out Object? value) => + public bool TryGetValue(string key, out object? value) => this.columns.TryGetValue(key, out value); /// @@ -136,16 +136,16 @@ IEnumerator IEnumerable.GetEnumerator() => /// /// Reads the value of a column, used as the target of a bound dynamic member read. /// - private static readonly Func readColumn = + private static readonly Func readColumn = static (row, columnName) => row[columnName]; /// /// Writes the value of a column and returns it, used as the target of a bound dynamic member write. /// - private static readonly Func writeColumn = + private static readonly Func writeColumn = static (row, columnName, value) => row[columnName] = value; - private readonly IDictionary columns; + private readonly IDictionary columns; /// /// Binds member access on a to the columns of the row, so that row.Id resolves to @@ -215,14 +215,14 @@ public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicM Expression.Constant(writeColumn), this.GetRowExpression(), Expression.Constant(binder.Name), - Expression.Convert(value.Expression, typeof(Object)) + Expression.Convert(value.Expression, typeof(object)) ), this.GetTypeRestriction().Merge(value.Restrictions) ); } /// - public override IEnumerable GetDynamicMemberNames() => + public override IEnumerable GetDynamicMemberNames() => ((DataRow)this.Value!).Keys; /// diff --git a/src/DbConnectionPlus/Entities/EntityHelper.cs b/src/DbConnectionPlus/Entities/EntityHelper.cs index 1e5dbd3..7e01109 100644 --- a/src/DbConnectionPlus/Entities/EntityHelper.cs +++ b/src/DbConnectionPlus/Entities/EntityHelper.cs @@ -85,7 +85,7 @@ public static class EntityHelper /// public static ConstructorInfo? FindCompatibleConstructor( [DynamicallyAccessedMembers(EntityMemberTypes)] Type type, - (String Name, Type Type)[] expectedParameters) + (string Name, Type Type)[] expectedParameters) { ArgumentNullException.ThrowIfNull(type); ArgumentNullException.ThrowIfNull(expectedParameters); @@ -109,7 +109,7 @@ public static class EntityHelper expectedParameters .All(expectedParameter => parameters.Any(parameter => - !String.IsNullOrWhiteSpace(parameter.Name) && + !string.IsNullOrWhiteSpace(parameter.Name) && parameter.Name.Equals(expectedParameter.Name, StringComparison.OrdinalIgnoreCase) && ValueConverter.CanConvert(expectedParameter.Type, parameter.ParameterType) ) @@ -194,7 +194,7 @@ internal static void ResetEntityTypeMetadataCache() => /// unsynchronized assignment is deliberate: two threads racing here produce two equivalent invokers, and either /// one is correct. /// - private static Func CreatePropertyGetter(PropertyInfo property) + private static Func CreatePropertyGetter(PropertyInfo property) { MethodInvoker? getMethodInvoker = null; @@ -217,7 +217,7 @@ internal static void ResetEntityTypeMetadataCache() => /// unsynchronized assignment is deliberate: two threads racing here produce two equivalent invokers, and either /// one is correct. /// - private static Action CreatePropertySetter(PropertyInfo property) + private static Action CreatePropertySetter(PropertyInfo property) { MethodInvoker? setMethodInvoker = null; @@ -242,20 +242,20 @@ internal static void ResetEntityTypeMetadataCache() => private static EntityTypeMetadata CreateEntityTypeMetadata( [DynamicallyAccessedMembers(EntityMemberTypes)] Type entityType) { - String tableName; + string tableName; DbConnectionPlusConfiguration.Instance.GetEntityTypeBuilders() .TryGetValue(entityType, out var entityTypeBuilder); if (entityTypeBuilder is not null) { - tableName = !String.IsNullOrWhiteSpace(entityTypeBuilder.TableName) + tableName = !string.IsNullOrWhiteSpace(entityTypeBuilder.TableName) ? entityTypeBuilder.TableName : entityType.Name; } else { - tableName = !String.IsNullOrWhiteSpace(entityType.GetCustomAttribute()?.Name) + tableName = !string.IsNullOrWhiteSpace(entityType.GetCustomAttribute()?.Name) ? entityType.GetCustomAttribute()?.Name! : entityType.Name; } @@ -275,7 +275,7 @@ entityTypeBuilder is not null && propertiesMetadata[i] = new( property.CanRead, property.CanWrite, - !String.IsNullOrWhiteSpace(propertyBuilder.ColumnName) + !string.IsNullOrWhiteSpace(propertyBuilder.ColumnName) ? propertyBuilder.ColumnName : property.Name, propertyBuilder.IsComputed, diff --git a/src/DbConnectionPlus/Entities/EntityPropertyMetadata.cs b/src/DbConnectionPlus/Entities/EntityPropertyMetadata.cs index f64b393..548567f 100644 --- a/src/DbConnectionPlus/Entities/EntityPropertyMetadata.cs +++ b/src/DbConnectionPlus/Entities/EntityPropertyMetadata.cs @@ -33,18 +33,18 @@ namespace RentADeveloper.DbConnectionPlus.Entities; /// /// The property type of the property. public sealed record EntityPropertyMetadata( - Boolean CanRead, - Boolean CanWrite, - String ColumnName, - Boolean IsComputed, - Boolean IsConcurrencyToken, - Boolean IsIdentity, - Boolean IsIgnored, - Boolean IsKey, - Boolean IsRowVersion, - Func? PropertyGetter, + bool CanRead, + bool CanWrite, + string ColumnName, + bool IsComputed, + bool IsConcurrencyToken, + bool IsIdentity, + bool IsIgnored, + bool IsKey, + bool IsRowVersion, + Func? PropertyGetter, PropertyInfo PropertyInfo, - String PropertyName, - Action? PropertySetter, + string PropertyName, + Action? PropertySetter, Type PropertyType ); diff --git a/src/DbConnectionPlus/Entities/EntityTypeMetadata.cs b/src/DbConnectionPlus/Entities/EntityTypeMetadata.cs index 59cd10b..5202b2c 100644 --- a/src/DbConnectionPlus/Entities/EntityTypeMetadata.cs +++ b/src/DbConnectionPlus/Entities/EntityTypeMetadata.cs @@ -44,9 +44,9 @@ namespace RentADeveloper.DbConnectionPlus.Entities; /// public sealed record EntityTypeMetadata( Type EntityType, - String TableName, + string TableName, IReadOnlyList AllProperties, - IReadOnlyDictionary AllPropertiesByPropertyName, + IReadOnlyDictionary AllPropertiesByPropertyName, IReadOnlyList ComputedProperties, IReadOnlyList ConcurrencyTokenProperties, IReadOnlyList DatabaseGeneratedProperties, diff --git a/src/DbConnectionPlus/Exceptions/DbUpdateConcurrencyException.cs b/src/DbConnectionPlus/Exceptions/DbUpdateConcurrencyException.cs index 01b2de5..c6d224b 100644 --- a/src/DbConnectionPlus/Exceptions/DbUpdateConcurrencyException.cs +++ b/src/DbConnectionPlus/Exceptions/DbUpdateConcurrencyException.cs @@ -12,7 +12,7 @@ public class DbUpdateConcurrencyException : Exception /// /// The error message. /// The entity that was involved in the concurrency violation. - public DbUpdateConcurrencyException(String message, Object entity) : base(message) => + public DbUpdateConcurrencyException(string message, object entity) : base(message) => this.Entity = entity; /// @@ -26,7 +26,7 @@ public DbUpdateConcurrencyException() /// Initializes a new instance of the class. /// /// The error message. - public DbUpdateConcurrencyException(String message) : base(message) + public DbUpdateConcurrencyException(string message) : base(message) { } @@ -35,12 +35,12 @@ public DbUpdateConcurrencyException(String message) : base(message) /// /// The error message. /// The inner exception. - public DbUpdateConcurrencyException(String message, Exception innerException) : base(message, innerException) + public DbUpdateConcurrencyException(string message, Exception innerException) : base(message, innerException) { } /// /// The entity that was involved in the concurrency violation. /// - public Object? Entity { get; set; } + public object? Entity { get; set; } } diff --git a/src/DbConnectionPlus/Extensions/DbDataReaderExtensions.cs b/src/DbConnectionPlus/Extensions/DbDataReaderExtensions.cs index 55d660a..1a4298e 100644 --- a/src/DbConnectionPlus/Extensions/DbDataReaderExtensions.cs +++ b/src/DbConnectionPlus/Extensions/DbDataReaderExtensions.cs @@ -17,11 +17,11 @@ internal static class DbDataReaderExtensions /// The order of names in the array corresponds to the order of the fields in . /// /// is . - internal static String[] GetFieldNames(this DbDataReader dataReader) + internal static string[] GetFieldNames(this DbDataReader dataReader) { ArgumentNullException.ThrowIfNull(dataReader); - var result = new String[dataReader.FieldCount]; + var result = new string[dataReader.FieldCount]; for (var i = 0; i < dataReader.FieldCount; i++) { diff --git a/src/DbConnectionPlus/Extensions/Int32Extensions.cs b/src/DbConnectionPlus/Extensions/Int32Extensions.cs index d4eef46..bab73d5 100644 --- a/src/DbConnectionPlus/Extensions/Int32Extensions.cs +++ b/src/DbConnectionPlus/Extensions/Int32Extensions.cs @@ -6,7 +6,7 @@ namespace RentADeveloper.DbConnectionPlus.Extensions; /// -/// Provides extension methods for the type . +/// Provides extension methods for the type . /// internal static class Int32Extensions { @@ -16,7 +16,7 @@ internal static class Int32Extensions /// /// The number to ordinalize. /// The ordinalized number in english notation. - internal static String OrdinalizeEnglish(this Int32 value) => + internal static string OrdinalizeEnglish(this int value) => value.Ordinalize(englishCulture); private static readonly CultureInfo englishCulture = new("en-US"); diff --git a/src/DbConnectionPlus/Extensions/ObjectExtensions.cs b/src/DbConnectionPlus/Extensions/ObjectExtensions.cs index 30a0fca..ed98c2b 100644 --- a/src/DbConnectionPlus/Extensions/ObjectExtensions.cs +++ b/src/DbConnectionPlus/Extensions/ObjectExtensions.cs @@ -4,7 +4,7 @@ namespace RentADeveloper.DbConnectionPlus.Extensions; /// -/// Provides extension methods for the type . +/// Provides extension methods for the type . /// internal static class ObjectExtensions { @@ -17,11 +17,11 @@ internal static class ObjectExtensions /// /// /// Sequences are rendered element by element as [a,b,c]; a value of any other unhandled type is - /// rendered via . Nothing here reflects over the value, so the whole path stays + /// rendered via . Nothing here reflects over the value, so the whole path stays /// usable under Native AOT and trimming — which matters, because this method builds the message of every /// conversion failure and must not fail while doing so. /// - internal static String ToDebugString(this Object? value) => + internal static string ToDebugString(this object? value) => value switch { null => "{null}", @@ -35,7 +35,7 @@ internal static String ToDebugString(this Object? value) => /// The value of which to get the string representation. /// The current nesting depth, used to bound the recursion into nested sequences. /// A string representation of . - private static String FormatValue(Object? value, Int32 depth) => + private static string FormatValue(object? value, int depth) => value switch { null => @@ -44,16 +44,16 @@ private static String FormatValue(Object? value, Int32 depth) => DBNull => "{DBNull}", - Boolean booleanValue => + bool booleanValue => booleanValue ? "True" : "False", - Byte byteValue => + byte byteValue => byteValue.ToString("G", CultureInfo.InvariantCulture), - Byte[] bytesValue => + byte[] bytesValue => Convert.ToBase64String(bytesValue), - Char charValue => + char charValue => charValue.ToString(), DateTime dateTimeValue => @@ -62,10 +62,10 @@ private static String FormatValue(Object? value, Int32 depth) => DateTimeOffset dateTimeOffsetValue => dateTimeOffsetValue.ToString("O", CultureInfo.InvariantCulture), - Decimal decimalValue => + decimal decimalValue => decimalValue.ToString("N", CultureInfo.InvariantCulture), - Double doubleValue => + double doubleValue => doubleValue.ToString("G17", CultureInfo.InvariantCulture), Enum enumValue => @@ -74,37 +74,37 @@ private static String FormatValue(Object? value, Int32 depth) => Guid guidValue => guidValue.ToString("D", CultureInfo.InvariantCulture), - Int16 int16Value => + short int16Value => int16Value.ToString("G", CultureInfo.InvariantCulture), - Int32 int32Value => + int int32Value => int32Value.ToString("G", CultureInfo.InvariantCulture), - Int64 int64Value => + long int64Value => int64Value.ToString("G", CultureInfo.InvariantCulture), IntPtr intPtrValue => intPtrValue.ToString("G", CultureInfo.InvariantCulture), - SByte sbyteValue => + sbyte sbyteValue => sbyteValue.ToString("G", CultureInfo.InvariantCulture), - Single singleValue => + float singleValue => singleValue.ToString("G9", CultureInfo.InvariantCulture), - String stringValue => + string stringValue => stringValue, TimeSpan timeSpanValue => timeSpanValue.ToString("c", CultureInfo.InvariantCulture), - UInt16 uint16Value => + ushort uint16Value => uint16Value.ToString("G", CultureInfo.InvariantCulture), - UInt32 uint32Value => + uint uint32Value => uint32Value.ToString("G", CultureInfo.InvariantCulture), - UInt64 uint64Value => + ulong uint64Value => uint64Value.ToString("G", CultureInfo.InvariantCulture), UIntPtr uintPtrValue => @@ -119,7 +119,7 @@ private static String FormatValue(Object? value, Int32 depth) => // are unavailable under Native AOT, so a conversion error would itself fail while building // its message. A type that renders as its own name here simply has no ToString override. _ => - value.ToString() ?? String.Empty + value.ToString() ?? string.Empty }; /// @@ -128,13 +128,13 @@ private static String FormatValue(Object? value, Int32 depth) => /// The sequence of which to get the string representation. /// The nesting depth at which itself sits. /// A string representation of . - private static String FormatSequence(IEnumerable values, Int32 depth) => + private static string FormatSequence(IEnumerable values, int depth) => depth >= MaxSequenceDepth ? "[...]" - : "[" + String.Join(",", values.Cast().Select(item => FormatValue(item, depth + 1))) + "]"; + : "[" + string.Join(",", values.Cast().Select(item => FormatValue(item, depth + 1))) + "]"; /// /// The deepest sequence nesting that is rendered before the representation is truncated. /// - private const Int32 MaxSequenceDepth = 10; + private const int MaxSequenceDepth = 10; } diff --git a/src/DbConnectionPlus/Extensions/TypeExtensions.cs b/src/DbConnectionPlus/Extensions/TypeExtensions.cs index b3e781a..df1178e 100644 --- a/src/DbConnectionPlus/Extensions/TypeExtensions.cs +++ b/src/DbConnectionPlus/Extensions/TypeExtensions.cs @@ -10,7 +10,7 @@ internal static class TypeExtensions { /// /// Determines whether this type is a built-in .NET type - /// (e.g. , , , ...). + /// (e.g. , , , ...). /// /// The type to inspect. /// @@ -18,7 +18,7 @@ internal static class TypeExtensions /// /// is . [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Boolean IsBuiltInTypeOrNullableBuiltInType(this Type type) + internal static bool IsBuiltInTypeOrNullableBuiltInType(this Type type) { ArgumentNullException.ThrowIfNull(type); @@ -26,20 +26,20 @@ internal static Boolean IsBuiltInTypeOrNullableBuiltInType(this Type type) } /// - /// Determines whether this type is or . + /// Determines whether this type is or . /// /// The type to inspect. /// - /// if this type is or ; otherwise, + /// if this type is or ; otherwise, /// . /// /// is . [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Boolean IsCharOrNullableCharType(this Type type) + internal static bool IsCharOrNullableCharType(this Type type) { ArgumentNullException.ThrowIfNull(type); - return type == typeof(Char) || type == typeof(Char?); + return type == typeof(char) || type == typeof(char?); } /// @@ -52,7 +52,7 @@ internal static Boolean IsCharOrNullableCharType(this Type type) /// /// is . [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Boolean IsEnumOrNullableEnumType(this Type type) + internal static bool IsEnumOrNullableEnumType(this Type type) { ArgumentNullException.ThrowIfNull(type); @@ -69,7 +69,7 @@ internal static Boolean IsEnumOrNullableEnumType(this Type type) /// /// is . [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Boolean IsReferenceTypeOrNullableType(this Type type) + internal static bool IsReferenceTypeOrNullableType(this Type type) { ArgumentNullException.ThrowIfNull(type); @@ -86,7 +86,7 @@ internal static Boolean IsReferenceTypeOrNullableType(this Type type) /// /// is . [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Boolean IsValueTupleType(this Type type) + internal static bool IsValueTupleType(this Type type) { ArgumentNullException.ThrowIfNull(type); @@ -95,22 +95,22 @@ internal static Boolean IsValueTupleType(this Type type) private static readonly HashSet builtInTypes = [ - typeof(Boolean), - typeof(Byte), - typeof(SByte), - typeof(Char), - typeof(Decimal), - typeof(Double), - typeof(Single), - typeof(Int16), - typeof(UInt16), - typeof(Int32), - typeof(UInt32), - typeof(Int64), - typeof(UInt64), + typeof(bool), + typeof(byte), + typeof(sbyte), + typeof(char), + typeof(decimal), + typeof(double), + typeof(float), + typeof(short), + typeof(ushort), + typeof(int), + typeof(uint), + typeof(long), + typeof(ulong), typeof(IntPtr), typeof(UIntPtr), - typeof(String), + typeof(string), typeof(DateTime), typeof(DateOnly), typeof(DateTimeOffset), diff --git a/src/DbConnectionPlus/Helpers/NameHelper.cs b/src/DbConnectionPlus/Helpers/NameHelper.cs index 790f18f..75de15c 100644 --- a/src/DbConnectionPlus/Helpers/NameHelper.cs +++ b/src/DbConnectionPlus/Helpers/NameHelper.cs @@ -24,7 +24,7 @@ internal static class NameHelper /// The first character of the resulting name is converted to uppercase if it is a lowercase letter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static String CreateNameFromCallerArgumentExpression(ReadOnlySpan expression, Int32 maximumLength) + internal static string CreateNameFromCallerArgumentExpression(ReadOnlySpan expression, int maximumLength) { // Remove common prefixes: @@ -45,7 +45,7 @@ internal static String CreateNameFromCallerArgumentExpression(ReadOnlySpan var bufferLength = Math.Min(expression.Length, maximumLength); - var buffer = bufferLength <= 512 ? stackalloc Char[bufferLength] : new Char[bufferLength]; + var buffer = bufferLength <= 512 ? stackalloc char[bufferLength] : new char[bufferLength]; ref var expressionPointer = ref MemoryMarshal.GetReference(expression); ref var bufferPointer = ref MemoryMarshal.GetReference(buffer); @@ -57,9 +57,9 @@ internal static String CreateNameFromCallerArgumentExpression(ReadOnlySpan var character = Unsafe.Add(ref expressionPointer, i); if ( - (UInt32)(character - '0') <= 9 || // Digits - (UInt32)(character - 'A') <= 25 || // Uppercase letters - (UInt32)(character - 'a') <= 25 || // Lowercase letters + (uint)(character - '0') <= 9 || // Digits + (uint)(character - 'A') <= 25 || // Uppercase letters + (uint)(character - 'a') <= 25 || // Lowercase letters character == '_' ) { @@ -73,9 +73,9 @@ internal static String CreateNameFromCallerArgumentExpression(ReadOnlySpan } // Convert the first character to uppercase if necessary. - if (count != 0 && (UInt32)(buffer[0] - 'a') <= 25) + if (count != 0 && (uint)(buffer[0] - 'a') <= 25) { - buffer[0] = (Char)(buffer[0] - 32); + buffer[0] = (char)(buffer[0] - 32); } return new(buffer[..count]); diff --git a/src/DbConnectionPlus/Materializers/DataRowMaterializer.cs b/src/DbConnectionPlus/Materializers/DataRowMaterializer.cs index 3c38479..9e09ada 100644 --- a/src/DbConnectionPlus/Materializers/DataRowMaterializer.cs +++ b/src/DbConnectionPlus/Materializers/DataRowMaterializer.cs @@ -20,10 +20,10 @@ internal static DataRow Materialize(DbDataReader dataReader) { ArgumentNullException.ThrowIfNull(dataReader); - var values = new Object[dataReader.FieldCount]; + var values = new object[dataReader.FieldCount]; dataReader.GetValues(values); - var columns = new Dictionary(dataReader.FieldCount); + var columns = new Dictionary(dataReader.FieldCount); for (var ordinal = 0; ordinal < dataReader.FieldCount; ordinal++) { diff --git a/src/DbConnectionPlus/Materializers/EntityMaterializerFactory.cs b/src/DbConnectionPlus/Materializers/EntityMaterializerFactory.cs index 012a6c0..f18cb7a 100644 --- a/src/DbConnectionPlus/Materializers/EntityMaterializerFactory.cs +++ b/src/DbConnectionPlus/Materializers/EntityMaterializerFactory.cs @@ -24,7 +24,7 @@ internal static class EntityMaterializerFactory /// branch; the attribute exists so that the analyzer /// verifies that guard rather than so that a warning propagates. /// - private const String MaterializerRequiresDynamicCodeMessage = + private const string MaterializerRequiresDynamicCodeMessage = "Materializing entities compiles an expression tree at run time, which is not supported when the " + "application is published with Native AOT. Reach this only from a RuntimeFeature.IsDynamicCodeSupported " + "branch."; @@ -185,7 +185,7 @@ internal static Func CreateReflectionMaterializer< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbDataReader dataReader, - String[] dataReaderFieldNames, + string[] dataReaderFieldNames, Type[] dataReaderFieldTypes ) { @@ -246,7 +246,7 @@ .. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) /// private static Func CreateReflectionConstructorMaterializer( DbDataReader dataReader, - String[] dataReaderFieldNames, + string[] dataReaderFieldNames, Type[] dataReaderFieldTypes, ConstructorInfo compatibleConstructor ) @@ -262,7 +262,7 @@ ConstructorInfo compatibleConstructor var dataReaderFieldType = dataReaderFieldTypes[fieldOrdinal]; var constructorParameter = constructorParameters.First(p => - !String.IsNullOrWhiteSpace(p.Name) && + !string.IsNullOrWhiteSpace(p.Name) && p.Name.Equals(dataReaderFieldName, StringComparison.OrdinalIgnoreCase) && ValueConverter.CanConvert(dataReaderFieldType, p.ParameterType) ); @@ -319,7 +319,7 @@ private static Func CreateReflectionPropertyMaterializer< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbDataReader dataReader, - String[] dataReaderFieldNames, + string[] dataReaderFieldNames, Type[] dataReaderFieldTypes ) { @@ -400,8 +400,8 @@ Type[] dataReaderFieldTypes /// private static void GuardAgainstResultSetBindingNoProperties( Type entityType, - String[] dataReaderFieldNames, - Dictionary entityPropertiesByColumnName + string[] dataReaderFieldNames, + Dictionary entityPropertiesByColumnName ) { if (dataReaderFieldNames.Length == 0) @@ -416,7 +416,7 @@ Dictionary entityPropertiesByColumnName throw new InvalidOperationException( $"None of the {dataReaderFieldNames.Length} field(s) of the result set " + - $"({String.Join(", ", dataReaderFieldNames)}) could be mapped to a writable property of the entity " + + $"({string.Join(", ", dataReaderFieldNames)}) could be mapped to a writable property of the entity " + $"type {entityType}. Materializing the result set would return entities whose properties are all left " + "at their default values. Check that the field names of the result set match the property names, or " + "the mapped column names, of the entity type. If the application is trimmed or published with Native " + @@ -500,7 +500,7 @@ private static Delegate CreateMaterializer< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbDataReader dataReader, - String[] dataReaderFieldNames, + string[] dataReaderFieldNames, Type[] dataReaderFieldTypes ) { @@ -564,7 +564,7 @@ private static Delegate CreateExpressionMaterializer< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >( DbDataReader dataReader, - String[] dataReaderFieldNames, + string[] dataReaderFieldNames, Type[] dataReaderFieldTypes ) { @@ -580,8 +580,8 @@ Type[] dataReaderFieldTypes var dataReaderParameterExpression = Expression.Parameter(typeof(DbDataReader), "dataReader"); var dataReaderFieldValueExpressions = new Expression[dataReader.FieldCount]; - var fieldOrdinalToTargetType = new Dictionary(dataReader.FieldCount); - var fieldOrdinalToConstructorParameterIndex = new Dictionary(dataReader.FieldCount); + var fieldOrdinalToTargetType = new Dictionary(dataReader.FieldCount); + var fieldOrdinalToConstructorParameterIndex = new Dictionary(dataReader.FieldCount); var compatibleConstructor = EntityHelper.FindCompatibleConstructor( entityType, @@ -599,7 +599,7 @@ [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) for (var fieldOrdinal = 0; fieldOrdinal < dataReader.FieldCount; fieldOrdinal++) { var constructorParameter = constructorParameters.First(p => - !String.IsNullOrWhiteSpace(p.Name) && + !string.IsNullOrWhiteSpace(p.Name) && p.Name.Equals(dataReaderFieldNames[fieldOrdinal], StringComparison.OrdinalIgnoreCase) && ValueConverter.CanConvert(dataReaderFieldTypes[fieldOrdinal], p.ParameterType) ); @@ -701,7 +701,7 @@ [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) ? Expression.Default(targetType) : Expression.Throw( Expression.New( - typeof(InvalidCastException).GetConstructor([typeof(String)])!, + typeof(InvalidCastException).GetConstructor([typeof(string)])!, Expression.Constant( $"The column '{dataReaderFieldName}' returned by the SQL statement contains a " + $"NULL value, but the corresponding property of the type {entityType} is " + @@ -714,7 +714,7 @@ [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) var throwInvalidCastExceptionExpression = Expression.Throw( Expression.New( typeof(InvalidCastException).GetConstructor( - [typeof(String), typeof(Exception)] + [typeof(string), typeof(Exception)] )!, Expression.Constant( $"The column '{dataReaderFieldName}' returned by the SQL statement " + @@ -732,7 +732,7 @@ [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) Expression.Call( null, MaterializerFactoryHelper.MakeValueConverterConvertValueToTypeMethod(targetType), - Expression.Convert(getFieldValueCallExpression, typeof(Object)) + Expression.Convert(getFieldValueCallExpression, typeof(object)) ), targetType ), @@ -827,7 +827,7 @@ private static TEntity MaterializeEntityThroughConstructor( ReflectionColumnBinding[] constructorArgumentBindings ) { - var constructorArguments = new Object?[constructorArgumentBindings.Length]; + var constructorArguments = new object?[constructorArgumentBindings.Length]; for (var argumentIndex = 0; argumentIndex < constructorArgumentBindings.Length; argumentIndex++) { @@ -890,7 +890,7 @@ ReflectionPropertyBinding[] propertyBindings /// /// /// - private static Object? ReadFieldValue( + private static object? ReadFieldValue( DbDataReader dataReader, Type entityType, ReflectionColumnBinding columnBinding @@ -973,7 +973,7 @@ ReflectionColumnBinding columnBinding private static void ValidateDataReader( [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] Type entityType, DbDataReader dataReader, - String[] dataReaderFieldNames, + string[] dataReaderFieldNames, Type[] dataReaderFieldTypes ) { @@ -987,7 +987,7 @@ Type[] dataReaderFieldTypes var dataReaderFieldName = dataReaderFieldNames[fieldOrdinal]; var dataReaderFieldType = dataReaderFieldTypes[fieldOrdinal]; - if (String.IsNullOrWhiteSpace(dataReaderFieldName)) + if (string.IsNullOrWhiteSpace(dataReaderFieldName)) { throw new ArgumentException( $"The {(fieldOrdinal + 1).OrdinalizeEnglish()} column returned by the SQL statement does not " + @@ -1024,7 +1024,7 @@ [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) { var exampleConstructorSignature = "(" + - String.Join( + string.Join( ", ", dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => $"{type.Name} {name}") ) + @@ -1083,7 +1083,7 @@ [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) /// private readonly struct MaterializerCacheKey( Type entityType, - String[] dataReaderFieldNames, + string[] dataReaderFieldNames, Type[] dataReaderFieldTypes ) : IEquatable @@ -1094,17 +1094,17 @@ Type[] dataReaderFieldTypes public Type EntityType { get; } = entityType; /// - public Boolean Equals(MaterializerCacheKey other) => + public bool Equals(MaterializerCacheKey other) => this.EntityType == other.EntityType && this.DataReaderFieldNames.SequenceEqual(other.DataReaderFieldNames) && this.DataReaderFieldTypes.SequenceEqual(other.DataReaderFieldTypes); /// - public override Boolean Equals(Object? obj) => + public override bool Equals(object? obj) => obj is MaterializerCacheKey other && this.Equals(other); /// - public override Int32 GetHashCode() + public override int GetHashCode() { var hashCode = new HashCode(); @@ -1123,7 +1123,7 @@ public override Int32 GetHashCode() return hashCode.ToHashCode(); } - private String[] DataReaderFieldNames { get; } = dataReaderFieldNames; + private string[] DataReaderFieldNames { get; } = dataReaderFieldNames; private Type[] DataReaderFieldTypes { get; } = dataReaderFieldTypes; } @@ -1146,10 +1146,10 @@ public override Int32 GetHashCode() /// constructor parameter it is passed to. /// private readonly record struct ReflectionColumnBinding( - String FieldName, - Int32 FieldOrdinal, - Func GetFieldValue, - Boolean NeedsConversion, + string FieldName, + int FieldOrdinal, + Func GetFieldValue, + bool NeedsConversion, Type TargetType ); @@ -1163,6 +1163,6 @@ Type TargetType /// private readonly record struct ReflectionPropertyBinding( ReflectionColumnBinding Column, - Action PropertySetter + Action PropertySetter ); } diff --git a/src/DbConnectionPlus/Materializers/MaterializerFactoryHelper.cs b/src/DbConnectionPlus/Materializers/MaterializerFactoryHelper.cs index a188296..adc8c24 100644 --- a/src/DbConnectionPlus/Materializers/MaterializerFactoryHelper.cs +++ b/src/DbConnectionPlus/Materializers/MaterializerFactoryHelper.cs @@ -14,34 +14,34 @@ namespace RentADeveloper.DbConnectionPlus.Materializers; internal static class MaterializerFactoryHelper { /// - /// The method. + /// The method. /// internal static MethodInfo DbDataReaderGetValueMethod { get; } = typeof(DbDataReader) .GetMethod(nameof(DbDataReader.GetValue))!; /// - /// The method. + /// The method. /// // ReSharper disable once InconsistentNaming internal static MethodInfo DbDataReaderIsDBNullMethod { get; } = typeof(DbDataReader) .GetMethod(nameof(DbDataReader.IsDBNull))!; /// - /// The 'Chars' property of the type. + /// The 'Chars' property of the type. /// - internal static PropertyInfo StringCharsProperty { get; } = typeof(String) + internal static PropertyInfo StringCharsProperty { get; } = typeof(string) .GetProperty("Chars", BindingFlags.Instance | BindingFlags.Public)!; /// - /// The method. + /// The method. /// - internal static MethodInfo StringConcatMethod { get; } = typeof(String) - .GetMethod(nameof(String.Concat), [typeof(String), typeof(String), typeof(String)])!; + internal static MethodInfo StringConcatMethod { get; } = typeof(string) + .GetMethod(nameof(String.Concat), [typeof(string), typeof(string), typeof(string)])!; /// - /// The property. + /// The property. /// - internal static PropertyInfo StringLengthProperty { get; } = typeof(String) + internal static PropertyInfo StringLengthProperty { get; } = typeof(string) .GetProperty(nameof(String.Length), BindingFlags.Instance | BindingFlags.Public)!; /// @@ -128,8 +128,8 @@ internal static MethodInfo MakeValueConverterConvertValueToTypeMethod(Type targe internal static Expression CreateGetDbDataReaderFieldValueExpression( Expression dataReaderExpression, Expression fieldOrdinalExpression, - Int32 fieldOrdinal, - String? fieldName, + int fieldOrdinal, + string? fieldName, Type fieldType ) { @@ -137,7 +137,7 @@ Type fieldType ArgumentNullException.ThrowIfNull(fieldOrdinalExpression); ArgumentNullException.ThrowIfNull(fieldType); - if (fieldType == typeof(Byte[])) + if (fieldType == typeof(byte[])) { // Special handling for byte arrays since DbDataReader does not have a GetBytes method that returns // a byte array directly. @@ -148,7 +148,7 @@ Type fieldType DbDataReaderGetValueMethod, fieldOrdinalExpression ), - typeof(Byte[]) + typeof(byte[]) ); } @@ -214,7 +214,7 @@ Type fieldType if (!dbDataReaderTypedGetMethods.TryGetValue(fieldType, out var dbDataReaderGetMethod)) { - if (!String.IsNullOrWhiteSpace(fieldName)) + if (!string.IsNullOrWhiteSpace(fieldName)) { throw new ArgumentException( $"The data type {fieldType} of the column '{fieldName}' returned by the SQL statement is not " + @@ -246,7 +246,7 @@ Type fieldType /// The field ordinal of the field to get the value from. /// The field name of the field to get the value from. /// The field type of the field to get the value from. - /// The created function. It returns the field value boxed in an . + /// The created function. It returns the field value boxed in an . /// /// The specified type is not supported. /// @@ -262,9 +262,9 @@ Type fieldType /// counterpart, so picking a different method here would make the two materializer paths disagree. /// /// - internal static Func CreateGetDbDataReaderFieldValueFunction( - Int32 fieldOrdinal, - String? fieldName, + internal static Func CreateGetDbDataReaderFieldValueFunction( + int fieldOrdinal, + string? fieldName, Type fieldType ) { @@ -279,7 +279,7 @@ Type fieldType if (!dbDataReaderTypedGetValueFunctions.TryGetValue(fieldType, out var dbDataReaderGetValueFunction)) { - if (!String.IsNullOrWhiteSpace(fieldName)) + if (!string.IsNullOrWhiteSpace(fieldName)) { throw new ArgumentException( $"The data type {fieldType} of the column '{fieldName}' returned by the SQL statement is not " + @@ -308,7 +308,7 @@ Type fieldType /// ; otherwise, . /// /// is . - internal static Boolean IsDbDataReaderTypedGetMethodAvailable(Type fieldType) + internal static bool IsDbDataReaderTypedGetMethodAvailable(Type fieldType) { ArgumentNullException.ThrowIfNull(fieldType); @@ -318,17 +318,17 @@ internal static Boolean IsDbDataReaderTypedGetMethodAvailable(Type fieldType) private static readonly Dictionary dbDataReaderTypedGetMethods = new() { - { typeof(Boolean), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetBoolean))! }, - { typeof(Byte), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetByte))! }, + { typeof(bool), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetBoolean))! }, + { typeof(byte), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetByte))! }, { typeof(DateTime), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetDateTime))! }, - { typeof(Decimal), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetDecimal))! }, - { typeof(Double), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetDouble))! }, - { typeof(Single), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetFloat))! }, + { typeof(decimal), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetDecimal))! }, + { typeof(double), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetDouble))! }, + { typeof(float), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetFloat))! }, { typeof(Guid), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetGuid))! }, - { typeof(Int16), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetInt16))! }, - { typeof(Int32), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetInt32))! }, - { typeof(Int64), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetInt64))! }, - { typeof(String), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetString))! } + { typeof(short), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetInt16))! }, + { typeof(int), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetInt32))! }, + { typeof(long), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetInt64))! }, + { typeof(string), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetString))! } }; /// @@ -339,20 +339,20 @@ internal static Boolean IsDbDataReaderTypedGetMethodAvailable(Type fieldType) /// The key set must stay identical to the key set of , otherwise the /// two materializer paths disagree on which field types are supported. /// - private static readonly Dictionary> dbDataReaderTypedGetValueFunctions = + private static readonly Dictionary> dbDataReaderTypedGetValueFunctions = new() { - { typeof(Boolean), static (dataReader, fieldOrdinal) => dataReader.GetBoolean(fieldOrdinal) }, - { typeof(Byte), static (dataReader, fieldOrdinal) => dataReader.GetByte(fieldOrdinal) }, + { typeof(bool), static (dataReader, fieldOrdinal) => dataReader.GetBoolean(fieldOrdinal) }, + { typeof(byte), static (dataReader, fieldOrdinal) => dataReader.GetByte(fieldOrdinal) }, { typeof(DateTime), static (dataReader, fieldOrdinal) => dataReader.GetDateTime(fieldOrdinal) }, - { typeof(Decimal), static (dataReader, fieldOrdinal) => dataReader.GetDecimal(fieldOrdinal) }, - { typeof(Double), static (dataReader, fieldOrdinal) => dataReader.GetDouble(fieldOrdinal) }, - { typeof(Single), static (dataReader, fieldOrdinal) => dataReader.GetFloat(fieldOrdinal) }, + { typeof(decimal), static (dataReader, fieldOrdinal) => dataReader.GetDecimal(fieldOrdinal) }, + { typeof(double), static (dataReader, fieldOrdinal) => dataReader.GetDouble(fieldOrdinal) }, + { typeof(float), static (dataReader, fieldOrdinal) => dataReader.GetFloat(fieldOrdinal) }, { typeof(Guid), static (dataReader, fieldOrdinal) => dataReader.GetGuid(fieldOrdinal) }, - { typeof(Int16), static (dataReader, fieldOrdinal) => dataReader.GetInt16(fieldOrdinal) }, - { typeof(Int32), static (dataReader, fieldOrdinal) => dataReader.GetInt32(fieldOrdinal) }, - { typeof(Int64), static (dataReader, fieldOrdinal) => dataReader.GetInt64(fieldOrdinal) }, - { typeof(String), static (dataReader, fieldOrdinal) => dataReader.GetString(fieldOrdinal) } + { typeof(short), static (dataReader, fieldOrdinal) => dataReader.GetInt16(fieldOrdinal) }, + { typeof(int), static (dataReader, fieldOrdinal) => dataReader.GetInt32(fieldOrdinal) }, + { typeof(long), static (dataReader, fieldOrdinal) => dataReader.GetInt64(fieldOrdinal) }, + { typeof(string), static (dataReader, fieldOrdinal) => dataReader.GetString(fieldOrdinal) } }; /// @@ -362,7 +362,7 @@ internal static Boolean IsDbDataReaderTypedGetMethodAvailable(Type fieldType) /// private static readonly HashSet dbDataReaderUntypedFieldTypes = [ - typeof(Byte[]), + typeof(byte[]), typeof(DateOnly), typeof(DateTimeOffset), typeof(TimeOnly), diff --git a/src/DbConnectionPlus/Materializers/ValueTupleMaterializerFactory.cs b/src/DbConnectionPlus/Materializers/ValueTupleMaterializerFactory.cs index 169a857..060161a 100644 --- a/src/DbConnectionPlus/Materializers/ValueTupleMaterializerFactory.cs +++ b/src/DbConnectionPlus/Materializers/ValueTupleMaterializerFactory.cs @@ -25,7 +25,7 @@ internal static class ValueTupleMaterializerFactory /// branch; the attribute exists so that the analyzer /// verifies that guard rather than so that a warning propagates. /// - internal const String MaterializerRequiresDynamicCodeMessage = + internal const string MaterializerRequiresDynamicCodeMessage = "Materializing value tuples compiles an expression tree at run time, which is not supported when the " + "application is published with Native AOT. Reach this only from a RuntimeFeature.IsDynamicCodeSupported " + "branch."; @@ -60,7 +60,7 @@ internal static class ValueTupleMaterializerFactory /// The number of fields a value tuple holds before the runtime represents the remaining ones as a nested value /// tuple in its Rest field. /// - private const Int32 ValueTupleFieldCountBeforeNesting = 7; + private const int ValueTupleFieldCountBeforeNesting = 7; /// /// Gets a materializer function that materializes the data in a to an instance of the @@ -232,7 +232,7 @@ internal static Func CreateReflectionMaterializer< [DynamicallyAccessedMembers(ValueTupleMemberTypes)] TValueTuple >( DbDataReader dataReader, - String[] dataReaderFieldNames, + string[] dataReaderFieldNames, Type[] dataReaderFieldTypes ) { @@ -326,7 +326,7 @@ private static Delegate CreateMaterializer< >( Type[] valueTupleFieldTypes, DbDataReader dataReader, - String[] dataReaderFieldNames, + string[] dataReaderFieldNames, Type[] dataReaderFieldTypes ) { @@ -377,7 +377,7 @@ private static Delegate CreateExpressionMaterializer< >( Type[] valueTupleFieldTypes, DbDataReader dataReader, - String[] dataReaderFieldNames, + string[] dataReaderFieldNames, Type[] dataReaderFieldTypes ) { @@ -452,7 +452,7 @@ Type[] dataReaderFieldTypes ? Expression.Default(targetType) : Expression.Throw( Expression.New( - typeof(InvalidCastException).GetConstructor([typeof(String)])!, + typeof(InvalidCastException).GetConstructor([typeof(string)])!, Expression.Constant( $"The {columnNameOrPosition} returned by the SQL statement contains a NULL " + $"value, but the corresponding field of the value tuple type {valueTupleType} " + @@ -465,7 +465,7 @@ Type[] dataReaderFieldTypes var throwInvalidCastExceptionExpression = Expression.Throw( Expression.New( typeof(InvalidCastException).GetConstructor( - [typeof(String), typeof(Exception)] + [typeof(string), typeof(Exception)] )!, Expression.Constant( $"The {columnNameOrPosition} returned by the SQL statement contains a " + @@ -483,7 +483,7 @@ Type[] dataReaderFieldTypes Expression.Call( null, MaterializerFactoryHelper.MakeValueConverterConvertValueToTypeMethod(targetType), - Expression.Convert(getFieldValueCallExpression, typeof(Object)) + Expression.Convert(getFieldValueCallExpression, typeof(object)) ), targetType ), @@ -561,8 +561,8 @@ Type[] dataReaderFieldTypes /// The name of the field, or - for a result set whose columns have no name, which a value tuple query is allowed /// to have because its fields are matched by position - the position of the field. /// - private static String GetColumnNameOrPosition(Int32 fieldOrdinal, String? dataReaderFieldName) => - !String.IsNullOrWhiteSpace(dataReaderFieldName) + private static string GetColumnNameOrPosition(int fieldOrdinal, string? dataReaderFieldName) => + !string.IsNullOrWhiteSpace(dataReaderFieldName) ? $"column '{dataReaderFieldName}'" : $"{(fieldOrdinal + 1).OrdinalizeEnglish()} column"; @@ -700,13 +700,13 @@ ReflectionColumnBinding[] columnBindings /// /// A field of the result set could not be assigned to the corresponding field of the value tuple. /// - private static Object?[] ReadFieldValues( + private static object?[] ReadFieldValues( DbDataReader dataReader, Type valueTupleType, ReflectionColumnBinding[] columnBindings ) { - var fieldValues = new Object?[columnBindings.Length]; + var fieldValues = new object?[columnBindings.Length]; for (var fieldOrdinal = 0; fieldOrdinal < columnBindings.Length; fieldOrdinal++) { @@ -732,7 +732,7 @@ ReflectionColumnBinding[] columnBindings /// This does the same as the tail of , which builds the /// same nesting out of instead of constructing it. /// - private static Object ConstructValueTuple(ConstructorInvoker[] valueTupleConstructors, Object?[] fieldValues) + private static object ConstructValueTuple(ConstructorInvoker[] valueTupleConstructors, object?[] fieldValues) { // In C# value tuples with more than 7 fields are represented as nested value tuples. // E.g. a ValueTuple with 15 fields is represented as: @@ -744,7 +744,7 @@ private static Object ConstructValueTuple(ConstructorInvoker[] valueTupleConstru // first constructor belong to the outermost value tuple, the last ones to the innermost value tuple. var fieldValueChunks = fieldValues.Chunk(ValueTupleFieldCountBeforeNesting).ToArray(); - Object? valueTuple = null; + object? valueTuple = null; // Now we create the nested value tuples from the inside out, by walking both arrays from their last entry // to their first one. When we are done valueTuple contains the outermost value tuple. @@ -790,7 +790,7 @@ private static Object ConstructValueTuple(ConstructorInvoker[] valueTupleConstru /// /// /// - private static Object? ReadFieldValue( + private static object? ReadFieldValue( DbDataReader dataReader, Type valueTupleType, ReflectionColumnBinding columnBinding @@ -924,7 +924,7 @@ private static void ValidateDataReader( [DynamicallyAccessedMembers(ValueTupleMemberTypes)] Type valueTupleType, Type[] valueTupleFieldTypes, DbDataReader dataReader, - String[] dataReaderFieldNames, + string[] dataReaderFieldNames, Type[] dataReaderFieldTypes ) { @@ -989,23 +989,23 @@ Type[] dataReaderFieldTypes /// private readonly struct MaterializerCacheKey( Type[] valueTupleFieldTypes, - String[] dataReaderFieldNames, + string[] dataReaderFieldNames, Type[] dataReaderFieldTypes ) : IEquatable { /// - public Boolean Equals(MaterializerCacheKey other) => + public bool Equals(MaterializerCacheKey other) => this.ValueTupleFieldTypes.SequenceEqual(other.ValueTupleFieldTypes) && this.DataReaderFieldNames.SequenceEqual(other.DataReaderFieldNames) && this.DataReaderFieldTypes.SequenceEqual(other.DataReaderFieldTypes); /// - public override Boolean Equals(Object? obj) => + public override bool Equals(object? obj) => obj is MaterializerCacheKey other && this.Equals(other); /// - public override Int32 GetHashCode() + public override int GetHashCode() { var hashCode = new HashCode(); @@ -1028,7 +1028,7 @@ public override Int32 GetHashCode() return hashCode.ToHashCode(); } - private String[] DataReaderFieldNames { get; } = dataReaderFieldNames; + private string[] DataReaderFieldNames { get; } = dataReaderFieldNames; private Type[] DataReaderFieldTypes { get; } = dataReaderFieldTypes; private Type[] ValueTupleFieldTypes { get; } = valueTupleFieldTypes; } @@ -1054,10 +1054,10 @@ public override Int32 GetHashCode() /// The type the field value is converted to - the type of the value tuple field it is assigned to. /// private readonly record struct ReflectionColumnBinding( - String ColumnNameOrPosition, - Int32 FieldOrdinal, - Func GetFieldValue, - Boolean NeedsConversion, + string ColumnNameOrPosition, + int FieldOrdinal, + Func GetFieldValue, + bool NeedsConversion, Type TargetType ); } diff --git a/src/DbConnectionPlus/Readers/CommandDisposingDataReaderDecorator.cs b/src/DbConnectionPlus/Readers/CommandDisposingDataReaderDecorator.cs index f838932..2a72798 100644 --- a/src/DbConnectionPlus/Readers/CommandDisposingDataReaderDecorator.cs +++ b/src/DbConnectionPlus/Readers/CommandDisposingDataReaderDecorator.cs @@ -58,28 +58,28 @@ CancellationToken commandCancellationToken } /// - public override Int32 Depth => this.dataReader.Depth; + public override int Depth => this.dataReader.Depth; /// - public override Int32 FieldCount => this.dataReader.FieldCount; + public override int FieldCount => this.dataReader.FieldCount; /// - public override Boolean HasRows => this.dataReader.HasRows; + public override bool HasRows => this.dataReader.HasRows; /// - public override Boolean IsClosed => this.dataReader.IsClosed; + public override bool IsClosed => this.dataReader.IsClosed; /// - public override Object this[Int32 ordinal] => this.dataReader[ordinal]; + public override object this[int ordinal] => this.dataReader[ordinal]; /// - public override Object this[String name] => this.dataReader[name]; + public override object this[string name] => this.dataReader[name]; /// - public override Int32 RecordsAffected => this.dataReader.RecordsAffected; + public override int RecordsAffected => this.dataReader.RecordsAffected; /// - public override Int32 VisibleFieldCount => this.dataReader.VisibleFieldCount; + public override int VisibleFieldCount => this.dataReader.VisibleFieldCount; /// public override void Close() => @@ -105,34 +105,34 @@ public override async ValueTask DisposeAsync() } /// - public override Boolean GetBoolean(Int32 ordinal) => + public override bool GetBoolean(int ordinal) => this.dataReader.GetBoolean(ordinal); /// - public override Byte GetByte(Int32 ordinal) => + public override byte GetByte(int ordinal) => this.dataReader.GetByte(ordinal); /// - public override Int64 GetBytes( - Int32 ordinal, - Int64 dataOffset, - Byte[]? buffer, - Int32 bufferOffset, - Int32 length + public override long GetBytes( + int ordinal, + long dataOffset, + byte[]? buffer, + int bufferOffset, + int length ) => this.dataReader.GetBytes(ordinal, dataOffset, buffer, bufferOffset, length); /// - public override Char GetChar(Int32 ordinal) => + public override char GetChar(int ordinal) => this.dataReader.GetChar(ordinal); /// - public override Int64 GetChars( - Int32 ordinal, - Int64 dataOffset, - Char[]? buffer, - Int32 bufferOffset, - Int32 length + public override long GetChars( + int ordinal, + long dataOffset, + char[]? buffer, + int bufferOffset, + int length ) => this.dataReader.GetChars(ordinal, dataOffset, buffer, bufferOffset, length); @@ -143,19 +143,19 @@ public override Task> GetColumnSchemaAsync( this.dataReader.GetColumnSchemaAsync(cancellationToken); /// - public override String GetDataTypeName(Int32 ordinal) => + public override string GetDataTypeName(int ordinal) => this.dataReader.GetDataTypeName(ordinal); /// - public override DateTime GetDateTime(Int32 ordinal) => + public override DateTime GetDateTime(int ordinal) => this.dataReader.GetDateTime(ordinal); /// - public override Decimal GetDecimal(Int32 ordinal) => + public override decimal GetDecimal(int ordinal) => this.dataReader.GetDecimal(ordinal); /// - public override Double GetDouble(Int32 ordinal) => + public override double GetDouble(int ordinal) => this.dataReader.GetDouble(ordinal); /// @@ -165,57 +165,57 @@ public override IEnumerator GetEnumerator() => /// [return: DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] - public override Type GetFieldType(Int32 ordinal) => + public override Type GetFieldType(int ordinal) => this.dataReader.GetFieldType(ordinal); /// - public override T GetFieldValue(Int32 ordinal) => + public override T GetFieldValue(int ordinal) => this.dataReader.GetFieldValue(ordinal); /// - public override Task GetFieldValueAsync(Int32 ordinal, CancellationToken cancellationToken) => + public override Task GetFieldValueAsync(int ordinal, CancellationToken cancellationToken) => this.dataReader.GetFieldValueAsync(ordinal, cancellationToken); /// - public override Single GetFloat(Int32 ordinal) => + public override float GetFloat(int ordinal) => this.dataReader.GetFloat(ordinal); /// - public override Guid GetGuid(Int32 ordinal) => + public override Guid GetGuid(int ordinal) => this.dataReader.GetGuid(ordinal); /// - public override Int16 GetInt16(Int32 ordinal) => + public override short GetInt16(int ordinal) => this.dataReader.GetInt16(ordinal); /// - public override Int32 GetInt32(Int32 ordinal) => + public override int GetInt32(int ordinal) => this.dataReader.GetInt32(ordinal); /// - public override Int64 GetInt64(Int32 ordinal) => + public override long GetInt64(int ordinal) => this.dataReader.GetInt64(ordinal); /// - public override String GetName(Int32 ordinal) => + public override string GetName(int ordinal) => this.dataReader.GetName(ordinal); /// - public override Int32 GetOrdinal(String name) => + public override int GetOrdinal(string name) => this.dataReader.GetOrdinal(name); /// [return: DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] - public override Type GetProviderSpecificFieldType(Int32 ordinal) => + public override Type GetProviderSpecificFieldType(int ordinal) => this.dataReader.GetProviderSpecificFieldType(ordinal); /// - public override Object GetProviderSpecificValue(Int32 ordinal) => + public override object GetProviderSpecificValue(int ordinal) => this.dataReader.GetProviderSpecificValue(ordinal); /// - public override Int32 GetProviderSpecificValues(Object[] values) => + public override int GetProviderSpecificValues(object[] values) => this.dataReader.GetProviderSpecificValues(values); /// @@ -227,46 +227,46 @@ public override Int32 GetProviderSpecificValues(Object[] values) => this.dataReader.GetSchemaTableAsync(cancellationToken); /// - public override Stream GetStream(Int32 ordinal) => + public override Stream GetStream(int ordinal) => this.dataReader.GetStream(ordinal); /// - public override String GetString(Int32 ordinal) => + public override string GetString(int ordinal) => this.dataReader.GetString(ordinal); /// - public override TextReader GetTextReader(Int32 ordinal) => + public override TextReader GetTextReader(int ordinal) => this.dataReader.GetTextReader(ordinal); /// - public override Object GetValue(Int32 ordinal) => + public override object GetValue(int ordinal) => this.dataReader.GetValue(ordinal); /// - public override Int32 GetValues(Object[] values) => + public override int GetValues(object[] values) => this.dataReader.GetValues(values); /// - public override Boolean IsDBNull(Int32 ordinal) => + public override bool IsDBNull(int ordinal) => this.dataReader.IsDBNull(ordinal); /// - public override Task IsDBNullAsync(Int32 ordinal, CancellationToken cancellationToken) => + public override Task IsDBNullAsync(int ordinal, CancellationToken cancellationToken) => this.dataReader.IsDBNullAsync(ordinal, cancellationToken); /// - public override Boolean NextResult() => + public override bool NextResult() => this.dataReader.NextResult(); /// - public override Task NextResultAsync(CancellationToken cancellationToken) => + public override Task NextResultAsync(CancellationToken cancellationToken) => this.dataReader.NextResultAsync(cancellationToken); /// /// /// The operation was canceled via a . /// - public override Boolean Read() + public override bool Read() { try { @@ -288,7 +288,7 @@ public override Boolean Read() /// /// The operation was canceled via a . /// - public override async Task ReadAsync(CancellationToken cancellationToken) + public override async Task ReadAsync(CancellationToken cancellationToken) { try { @@ -318,11 +318,11 @@ public override async Task ReadAsync(CancellationToken cancellationToke } /// - public override String? ToString() => + public override string? ToString() => this.dataReader.ToString(); /// - protected override void Dispose(Boolean disposing) + protected override void Dispose(bool disposing) { if (this.isDisposed) { @@ -344,5 +344,5 @@ protected override void Dispose(Boolean disposing) private readonly DbCommandDisposer commandDisposer; private readonly IDatabaseAdapter databaseAdapter; private readonly DbDataReader dataReader; - private Boolean isDisposed; + private bool isDisposed; } diff --git a/src/DbConnectionPlus/Readers/EnumerableReader.cs b/src/DbConnectionPlus/Readers/EnumerableReader.cs index 1b5dcd6..dcd2039 100644 --- a/src/DbConnectionPlus/Readers/EnumerableReader.cs +++ b/src/DbConnectionPlus/Readers/EnumerableReader.cs @@ -57,7 +57,7 @@ public EnumerableReader( [DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] Type valuesType, - String fieldName) + string fieldName) { ArgumentNullException.ThrowIfNull(values); ArgumentNullException.ThrowIfNull(valuesType); @@ -135,26 +135,26 @@ public EnumerableReader( } /// - public override Int32 Depth => 0; + public override int Depth => 0; /// - public override Int32 FieldCount => this.fieldNames.Length; + public override int FieldCount => this.fieldNames.Length; /// - public override Boolean HasRows => true; + public override bool HasRows => true; /// // ReSharper disable once ConvertToAutoPropertyWithPrivateSetter - public override Boolean IsClosed => this.isClosed; + public override bool IsClosed => this.isClosed; /// - public override Object this[Int32 ordinal] => this.GetValue(ordinal); + public override object this[int ordinal] => this.GetValue(ordinal); /// - public override Object this[String name] => this.GetValue(this.GetOrdinalOrThrow(name)); + public override object this[string name] => this.GetValue(this.GetOrdinalOrThrow(name)); /// - public override Int32 RecordsAffected => -1; + public override int RecordsAffected => -1; /// public override void Close() @@ -169,36 +169,36 @@ public override void Close() } /// - public override Boolean GetBoolean(Int32 ordinal) => - (Boolean)this.GetValue(ordinal); + public override bool GetBoolean(int ordinal) => + (bool)this.GetValue(ordinal); /// - public override Byte GetByte(Int32 ordinal) => - (Byte)this.GetValue(ordinal); + public override byte GetByte(int ordinal) => + (byte)this.GetValue(ordinal); /// /// Always thrown. - public override Int64 GetBytes( - Int32 ordinal, - Int64 dataOffset, - Byte[]? buffer, - Int32 bufferOffset, - Int32 length + public override long GetBytes( + int ordinal, + long dataOffset, + byte[]? buffer, + int bufferOffset, + int length ) => throw new NotImplementedException(); /// - public override Char GetChar(Int32 ordinal) => - (Char)this.GetValue(ordinal); + public override char GetChar(int ordinal) => + (char)this.GetValue(ordinal); /// /// Always thrown. - public override Int64 GetChars( - Int32 ordinal, - Int64 dataOffset, - Char[]? buffer, - Int32 bufferOffset, - Int32 length + public override long GetChars( + int ordinal, + long dataOffset, + char[]? buffer, + int bufferOffset, + int length ) => throw new NotImplementedException(); @@ -206,20 +206,20 @@ Int32 length /// /// The specified ordinal is not one of the ordinals the reader supports. /// - public override String GetDataTypeName(Int32 ordinal) => + public override string GetDataTypeName(int ordinal) => this.GetFieldType(ordinal).Name; /// - public override DateTime GetDateTime(Int32 ordinal) => + public override DateTime GetDateTime(int ordinal) => (DateTime)this.GetValue(ordinal); /// - public override Decimal GetDecimal(Int32 ordinal) => - (Decimal)this.GetValue(ordinal); + public override decimal GetDecimal(int ordinal) => + (decimal)this.GetValue(ordinal); /// - public override Double GetDouble(Int32 ordinal) => - (Double)this.GetValue(ordinal); + public override double GetDouble(int ordinal) => + (double)this.GetValue(ordinal); /// public override IEnumerator GetEnumerator() => @@ -240,7 +240,7 @@ public override IEnumerator GetEnumerator() => /// [return: DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] - public override Type GetFieldType(Int32 ordinal) + public override Type GetFieldType(int ordinal) { this.EnsureValidFieldOrdinal(ordinal); @@ -248,39 +248,39 @@ public override Type GetFieldType(Int32 ordinal) } /// - public override Single GetFloat(Int32 ordinal) => - (Single)this.GetValue(ordinal); + public override float GetFloat(int ordinal) => + (float)this.GetValue(ordinal); /// - public override Guid GetGuid(Int32 ordinal) => + public override Guid GetGuid(int ordinal) => (Guid)this.GetValue(ordinal); /// - public override Int16 GetInt16(Int32 ordinal) => - (Int16)this.GetValue(ordinal); + public override short GetInt16(int ordinal) => + (short)this.GetValue(ordinal); /// - public override Int32 GetInt32(Int32 ordinal) + public override int GetInt32(int ordinal) { var value = this.GetValue(ordinal); if (this.SerializesEnums && this.IsEnumColumn(ordinal) && value is Enum enumValue) { - return (Int32)(Object)enumValue; + return (int)(object)enumValue; } - return (Int32)value; + return (int)value; } /// - public override Int64 GetInt64(Int32 ordinal) => - (Int64)this.GetValue(ordinal); + public override long GetInt64(int ordinal) => + (long)this.GetValue(ordinal); /// /// /// The specified ordinal is not one of the ordinals the reader supports. /// - public override String GetName(Int32 ordinal) + public override string GetName(int ordinal) { this.EnsureValidFieldOrdinal(ordinal); @@ -296,7 +296,7 @@ public override String GetName(Int32 ordinal) /// In multi-column mode an unknown name yields -1 rather than an exception, which is what the /// bulk-copy APIs of the database providers expect - they probe for columns they may not find. /// - public override Int32 GetOrdinal(String name) => + public override int GetOrdinal(string name) => this.IsSingleColumn ? this.GetOrdinalOrThrow(name) : Array.IndexOf(this.fieldNames, name); @@ -314,7 +314,7 @@ public override DataTable GetSchemaTable() => throw new NotImplementedException(); /// - public override String GetString(Int32 ordinal) + public override string GetString(int ordinal) { var value = this.GetValue(ordinal); @@ -329,17 +329,17 @@ public override String GetString(Int32 ordinal) // that GetString is called to retrieve the value. Casting a Char to a String would throw an // InvalidCastException, so the conversion happens here. - return (value as Char?)?.ToString() ?? String.Empty; + return (value as char?)?.ToString() ?? string.Empty; } - return (String)value; + return (string)value; } /// /// /// The specified ordinal is not one of the ordinals the reader supports. /// - public override Object GetValue(Int32 ordinal) + public override object GetValue(int ordinal) { this.EnsureValidFieldOrdinal(ordinal); @@ -359,7 +359,7 @@ public override Object GetValue(Int32 ordinal) /// In multi-column mode a buffer shorter than is filled as far as it reaches and the /// number of values written is returned, as specifies. /// - public override Int32 GetValues(Object[] values) + public override int GetValues(object[] values) { ArgumentNullException.ThrowIfNull(values); @@ -392,14 +392,14 @@ public override Int32 GetValues(Object[] values) /// /// The specified ordinal is not one of the ordinals the reader supports. /// - public override Boolean IsDBNull(Int32 ordinal) => + public override bool IsDBNull(int ordinal) => this.GetValue(ordinal) is DBNull; /// - public override Boolean NextResult() => false; + public override bool NextResult() => false; /// - public override Boolean Read() + public override bool Read() { if (this.isClosed) { @@ -417,7 +417,7 @@ public override Boolean Read() } /// - protected override void Dispose(Boolean disposing) + protected override void Dispose(bool disposing) { if (this.isDisposed) { @@ -437,18 +437,18 @@ protected override void Dispose(Boolean disposing) /// /// Gets a value indicating whether the reader reads a single column whose value is the sequence element itself. /// - private Boolean IsSingleColumn => this.valuesType is not null; + private bool IsSingleColumn => this.valuesType is not null; /// - /// Gets a value indicating whether the reader returns values as . + /// Gets a value indicating whether the reader returns values as . /// - private Boolean ReadsCharsAsStrings => + private bool ReadsCharsAsStrings => this.options.HasFlag(EnumerableReaderOptions.ReadCharsAsStrings); /// /// Gets a value indicating whether the reader serializes values while reading them. /// - private Boolean SerializesEnums => + private bool SerializesEnums => this.options.HasFlag(EnumerableReaderOptions.SerializeEnums); /// @@ -472,7 +472,7 @@ private void DisposeEnumerator() /// /// The specified ordinal is not one of the ordinals the reader supports. /// - private void EnsureValidFieldOrdinal(Int32 ordinal) + private void EnsureValidFieldOrdinal(int ordinal) { if (ordinal >= 0 && ordinal < this.FieldCount) { @@ -497,7 +497,7 @@ private void EnsureValidFieldOrdinal(Int32 ordinal) /// The type passed to the constructor if the reader reads a single column; otherwise the type of the property /// the column is mapped to. /// - private Type GetColumnType(Int32 ordinal) => + private Type GetColumnType(int ordinal) => this.valuesType ?? this.properties[ordinal].PropertyType; /// @@ -508,7 +508,7 @@ private Type GetColumnType(Int32 ordinal) => /// /// The reader does not have a field with the specified name . /// - private Int32 GetOrdinalOrThrow(String name) + private int GetOrdinalOrThrow(string name) { var ordinal = Array.IndexOf(this.fieldNames, name); @@ -523,7 +523,7 @@ private Int32 GetOrdinalOrThrow(String name) ? $"The specified field name '{name}' is not supported. The only supported field name is " + $"'{this.fieldNames[0]}'." : $"The specified field name '{name}' is not supported. The supported field names are " + - $"'{String.Join("', '", this.fieldNames)}'." + $"'{string.Join("', '", this.fieldNames)}'." ); } @@ -535,7 +535,7 @@ private Int32 GetOrdinalOrThrow(String name) /// if the column is mapped to an property; otherwise, /// . /// - private Boolean IsEnumColumn(Int32 ordinal) => + private bool IsEnumColumn(int ordinal) => this.GetColumnType(ordinal).IsEnumOrNullableEnumType(); /// @@ -543,7 +543,7 @@ private Boolean IsEnumColumn(Int32 ordinal) => /// /// The value to serialize. /// The serialized value. - private Object SerializeValue(Object value) + private object SerializeValue(object value) { if (this.SerializesEnums && value is Enum enumValue) { @@ -553,7 +553,7 @@ private Object SerializeValue(Object value) ); } - if (this.ReadsCharsAsStrings && value is Char charValue) + if (this.ReadsCharsAsStrings && value is char charValue) { // The data readers of all major database systems return the type String for CHAR columns. // So we mimic the same behavior for consistency. @@ -578,7 +578,7 @@ private Object SerializeValue(Object value) /// the base class puts on /// ; see the remarks there. A type that is neither a supported built-in /// type nor covered by — an outside MySQL, most notably — is - /// reported as . Returning the runtime property type would violate the inherited trimming + /// reported as . Returning the runtime property type would violate the inherited trimming /// contract because PropertyInfo.PropertyType carries no member annotation. No caller inside this library /// reads that fallback: PostgreSqlTemporaryTableBuilder, the one place that would inspect the reader's /// field types, derives its NpgsqlDbType values from the entity metadata instead. @@ -591,7 +591,7 @@ private static Type MapReportedFieldType(Type propertyType, EnumerableReaderOpti { if (!options.HasFlag(EnumerableReaderOptions.SerializeEnums)) { - return typeof(Object); + return typeof(object); } var enumSerializationMode = DbConnectionPlusConfiguration.Instance.EnumSerializationMode; @@ -599,10 +599,10 @@ private static Type MapReportedFieldType(Type propertyType, EnumerableReaderOpti return enumSerializationMode switch { EnumSerializationMode.Strings => - typeof(String), + typeof(string), EnumSerializationMode.Integers => - typeof(Int32), + typeof(int), _ => ThrowInvalidEnumSerializationModeException(enumSerializationMode) }; @@ -613,7 +613,7 @@ private static Type MapReportedFieldType(Type propertyType, EnumerableReaderOpti // The data readers of all major database systems return the type String for CHAR columns. // So we mimic the same behavior for consistency. - return typeof(String); + return typeof(string); } return MapBuiltInFieldType(Nullable.GetUnderlyingType(propertyType) ?? propertyType); @@ -641,7 +641,7 @@ private static Type ThrowInvalidEnumSerializationModeException(EnumSerialization /// /// The non-nullable type of the property the column is mapped to. /// - /// The statically known type the column is reported as, or for a type this library does + /// The statically known type the column is reported as, or for a type this library does /// not store in a temporary table. /// /// @@ -653,74 +653,74 @@ private static Type ThrowInvalidEnumSerializationModeException(EnumSerialization DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] private static Type MapBuiltInFieldType(Type propertyType) { - if (propertyType == typeof(Boolean)) + if (propertyType == typeof(bool)) { - return typeof(Boolean); + return typeof(bool); } - if (propertyType == typeof(Byte)) + if (propertyType == typeof(byte)) { - return typeof(Byte); + return typeof(byte); } - if (propertyType == typeof(Byte[])) + if (propertyType == typeof(byte[])) { - return typeof(Byte[]); + return typeof(byte[]); } - if (propertyType == typeof(SByte)) + if (propertyType == typeof(sbyte)) { - return typeof(SByte); + return typeof(sbyte); } - if (propertyType == typeof(Char)) + if (propertyType == typeof(char)) { - return typeof(Char); + return typeof(char); } - if (propertyType == typeof(Decimal)) + if (propertyType == typeof(decimal)) { - return typeof(Decimal); + return typeof(decimal); } - if (propertyType == typeof(Double)) + if (propertyType == typeof(double)) { - return typeof(Double); + return typeof(double); } - if (propertyType == typeof(Single)) + if (propertyType == typeof(float)) { - return typeof(Single); + return typeof(float); } - if (propertyType == typeof(Int16)) + if (propertyType == typeof(short)) { - return typeof(Int16); + return typeof(short); } - if (propertyType == typeof(UInt16)) + if (propertyType == typeof(ushort)) { - return typeof(UInt16); + return typeof(ushort); } - if (propertyType == typeof(Int32)) + if (propertyType == typeof(int)) { - return typeof(Int32); + return typeof(int); } - if (propertyType == typeof(UInt32)) + if (propertyType == typeof(uint)) { - return typeof(UInt32); + return typeof(uint); } - if (propertyType == typeof(Int64)) + if (propertyType == typeof(long)) { - return typeof(Int64); + return typeof(long); } - if (propertyType == typeof(UInt64)) + if (propertyType == typeof(ulong)) { - return typeof(UInt64); + return typeof(ulong); } if (propertyType == typeof(IntPtr)) @@ -733,9 +733,9 @@ private static Type MapBuiltInFieldType(Type propertyType) return typeof(UIntPtr); } - if (propertyType == typeof(String)) + if (propertyType == typeof(string)) { - return typeof(String); + return typeof(string); } if (propertyType == typeof(DateTime)) @@ -768,18 +768,18 @@ private static Type MapBuiltInFieldType(Type propertyType) return typeof(Guid); } - return typeof(Object); + return typeof(object); } private readonly IEnumerator enumerator; - private readonly String[] fieldNames; + private readonly string[] fieldNames; private readonly EnumerableReaderOptions options; private readonly EntityPropertyMetadata[] properties; [DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] private readonly Type? valuesType; - private Object? current; - private Boolean isClosed; - private Boolean isDisposed; - private Boolean isEnumeratorDisposed; + private object? current; + private bool isClosed; + private bool isDisposed; + private bool isEnumeratorDisposed; } diff --git a/src/DbConnectionPlus/Readers/EnumerableReaderOptions.cs b/src/DbConnectionPlus/Readers/EnumerableReaderOptions.cs index 00aff8c..9a2e831 100644 --- a/src/DbConnectionPlus/Readers/EnumerableReaderOptions.cs +++ b/src/DbConnectionPlus/Readers/EnumerableReaderOptions.cs @@ -8,7 +8,7 @@ namespace RentADeveloper.DbConnectionPlus.Readers; /// /// /// These flags exist because the temporary-table builders disagree deliberately: MySQL serializes -/// and values while it reads them, and SQL Server, SQLite, PostgreSQL and +/// and values while it reads them, and SQL Server, SQLite, PostgreSQL and /// Oracle hand the raw values to their bulk-copy APIs. That asymmetry is intentional and predates the AOT work — /// do not level it out here. /// @@ -27,8 +27,8 @@ internal enum EnumerableReaderOptions SerializeEnums = 1, /// - /// Report columns as and return their values as - /// , mirroring what the data readers of the major database systems do for CHAR columns. + /// Report columns as and return their values as + /// , mirroring what the data readers of the major database systems do for CHAR columns. /// ReadCharsAsStrings = 2 } diff --git a/src/DbConnectionPlus/SqlStatements/InterpolatedParameter.cs b/src/DbConnectionPlus/SqlStatements/InterpolatedParameter.cs index 0558a20..bb6f71c 100644 --- a/src/DbConnectionPlus/SqlStatements/InterpolatedParameter.cs +++ b/src/DbConnectionPlus/SqlStatements/InterpolatedParameter.cs @@ -11,5 +11,5 @@ namespace RentADeveloper.DbConnectionPlus.SqlStatements; /// This is if no name could be inferred. /// /// The value of the parameter. -public record InterpolatedParameter(String? InferredName, Object? Value) +public record InterpolatedParameter(string? InferredName, object? Value) : IInterpolatedSqlStatementFragment; diff --git a/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatement.cs b/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatement.cs index 9d15306..2fa5730 100644 --- a/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatement.cs +++ b/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatement.cs @@ -34,7 +34,7 @@ public struct InterpolatedSqlStatement : IEquatable [EditorBrowsable(EditorBrowsableState.Never)] // ReSharper disable once UnusedParameter.Local #pragma warning disable RCS1163 // Unused parameter - public InterpolatedSqlStatement(Int32 literalLength, Int32 formattedCount) + public InterpolatedSqlStatement(int literalLength, int formattedCount) #pragma warning restore RCS1163 // Unused parameter { this.fragments = new(formattedCount); @@ -66,7 +66,7 @@ public InterpolatedSqlStatement(Int32 literalLength, Int32 formattedCount) /// If a parameter value is an , it is serialized according to /// . /// - public InterpolatedSqlStatement(String code, params (String Name, Object? Value)[] parameters) + public InterpolatedSqlStatement(string code, params (string Name, object? Value)[] parameters) { ArgumentNullException.ThrowIfNull(code); ArgumentNullException.ThrowIfNull(parameters); @@ -87,7 +87,7 @@ public InterpolatedSqlStatement(String code, params (String Name, Object? Value) throw new ArgumentException( "The specified parameters have the following duplicate parameter names: " + - $"{String.Join(", ", duplicateParameterNames)}. Make sure each parameter name is only used once.", + $"{string.Join(", ", duplicateParameterNames)}. Make sure each parameter name is only used once.", nameof(parameters) ); } @@ -114,7 +114,7 @@ public InterpolatedSqlStatement(String code, params (String Name, Object? Value) /// It is not intended to be called by user code. /// [EditorBrowsable(EditorBrowsableState.Never)] - public void AppendFormatted(T? value, Int32 alignment = 0, String? format = null) + public void AppendFormatted(T? value, int alignment = 0, string? format = null) { switch (value) { @@ -131,10 +131,10 @@ public void AppendFormatted(T? value, Int32 alignment = 0, String? format = n var formattedValue = value switch { - String stringValue => stringValue, + string stringValue => stringValue, IFormattable formattable => formattable.ToString(format, CultureInfo.InvariantCulture), - null => String.Empty, - _ => value.ToString() ?? String.Empty + null => string.Empty, + _ => value.ToString() ?? string.Empty }; if (alignment != 0) @@ -147,12 +147,12 @@ public void AppendFormatted(T? value, Int32 alignment = 0, String? format = n if (alignment > 0) { // Right-align: - this.fragments.Add(new Literal(new String(' ', padding) + formattedValue)); + this.fragments.Add(new Literal(new string(' ', padding) + formattedValue)); } else { // Left-align: - this.fragments.Add(new Literal(formattedValue + new String(' ', padding))); + this.fragments.Add(new Literal(formattedValue + new string(' ', padding))); } break; @@ -173,7 +173,7 @@ public void AppendFormatted(T? value, Int32 alignment = 0, String? format = n /// It is not intended to be called by user code. /// [EditorBrowsable(EditorBrowsableState.Never)] - public void AppendLiteral(String? value) + public void AppendLiteral(string? value) { if (value is not null) { @@ -182,15 +182,15 @@ public void AppendLiteral(String? value) } /// - public readonly Boolean Equals(InterpolatedSqlStatement other) => + public readonly bool Equals(InterpolatedSqlStatement other) => this.fragments.SequenceEqual(other.Fragments); /// - public readonly override Boolean Equals(Object? obj) => + public readonly override bool Equals(object? obj) => obj is InterpolatedSqlStatement other && this.Equals(other); /// - public readonly override Int32 GetHashCode() + public readonly override int GetHashCode() { var hashCode = new HashCode(); @@ -203,9 +203,9 @@ public readonly override Int32 GetHashCode() } /// - public readonly override String ToString() + public readonly override string ToString() { - using var stringBuilder = new ValueStringBuilder(stackalloc Char[500]); + using var stringBuilder = new ValueStringBuilder(stackalloc char[500]); stringBuilder.AppendLine("SQL Statement"); stringBuilder.AppendLine(""); @@ -213,7 +213,7 @@ public readonly override String ToString() stringBuilder.AppendLine("Statement Code"); stringBuilder.AppendLine("--------------"); - var parameters = new Dictionary(StringComparer.Ordinal); + var parameters = new Dictionary(StringComparer.Ordinal); var interpolatedTemporaryTables = new List(); foreach (var fragment in this.fragments) @@ -227,7 +227,7 @@ public readonly override String ToString() case InterpolatedParameter interpolatedParameter: var parameterName = interpolatedParameter.InferredName; - if (String.IsNullOrWhiteSpace(parameterName)) + if (string.IsNullOrWhiteSpace(parameterName)) { parameterName = "Parameter_" + (parameters.Count + 1).ToString(CultureInfo.InvariantCulture); } @@ -286,7 +286,7 @@ public readonly override String ToString() { stringBuilder.AppendLine(); stringBuilder.AppendLine(temporaryTable.Name); - stringBuilder.AppendLine(new String('-', temporaryTable.Name.Length)); + stringBuilder.AppendLine(new string('-', temporaryTable.Name.Length)); foreach (var value in temporaryTable.Values) { @@ -304,7 +304,7 @@ public readonly override String ToString() /// The string from which to create an instance of . /// /// is . - public static InterpolatedSqlStatement FromString(String value) + public static InterpolatedSqlStatement FromString(string value) { ArgumentNullException.ThrowIfNull(value); @@ -320,7 +320,7 @@ public static InterpolatedSqlStatement FromString(String value) /// if the two specified instances of are /// equal; otherwise, . /// - public static Boolean operator ==(InterpolatedSqlStatement left, InterpolatedSqlStatement right) => + public static bool operator ==(InterpolatedSqlStatement left, InterpolatedSqlStatement right) => left.Equals(right); /// @@ -328,7 +328,7 @@ public static InterpolatedSqlStatement FromString(String value) /// /// The string to convert to an instance of . /// is . - public static implicit operator InterpolatedSqlStatement(String value) + public static implicit operator InterpolatedSqlStatement(string value) { ArgumentNullException.ThrowIfNull(value); @@ -344,7 +344,7 @@ public static implicit operator InterpolatedSqlStatement(String value) /// if the two the specified instances of are /// unequal; otherwise, . /// - public static Boolean operator !=(InterpolatedSqlStatement left, InterpolatedSqlStatement right) => + public static bool operator !=(InterpolatedSqlStatement left, InterpolatedSqlStatement right) => !(left == right); /// diff --git a/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatementDebugView.cs b/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatementDebugView.cs index 81edad7..6b219ca 100644 --- a/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatementDebugView.cs +++ b/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatementDebugView.cs @@ -12,7 +12,7 @@ internal sealed class InterpolatedSqlStatementDebugView(InterpolatedSqlStatement /// /// The debug view of the SQL statement. /// - public String DebugView => + public string DebugView => statement.ToString(); /// diff --git a/src/DbConnectionPlus/SqlStatements/InterpolatedTemporaryTable.cs b/src/DbConnectionPlus/SqlStatements/InterpolatedTemporaryTable.cs index 368902d..f78f71a 100644 --- a/src/DbConnectionPlus/SqlStatements/InterpolatedTemporaryTable.cs +++ b/src/DbConnectionPlus/SqlStatements/InterpolatedTemporaryTable.cs @@ -16,7 +16,7 @@ namespace RentADeveloper.DbConnectionPlus.SqlStatements; /// property the trimmer would not see that requirement. /// public record InterpolatedTemporaryTable( - String Name, + string Name, IEnumerable Values, [property: DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] [param: DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] diff --git a/src/DbConnectionPlus/SqlStatements/Literal.cs b/src/DbConnectionPlus/SqlStatements/Literal.cs index 209e528..67371ef 100644 --- a/src/DbConnectionPlus/SqlStatements/Literal.cs +++ b/src/DbConnectionPlus/SqlStatements/Literal.cs @@ -7,4 +7,4 @@ namespace RentADeveloper.DbConnectionPlus.SqlStatements; /// A fragment of an interpolated SQL statement that represents a literal string. /// /// The literal string. -internal record Literal(String Value) : IInterpolatedSqlStatementFragment; +internal record Literal(string Value) : IInterpolatedSqlStatementFragment; diff --git a/src/DbConnectionPlus/SqlStatements/Parameter.cs b/src/DbConnectionPlus/SqlStatements/Parameter.cs index aa5cf34..2cfa0d1 100644 --- a/src/DbConnectionPlus/SqlStatements/Parameter.cs +++ b/src/DbConnectionPlus/SqlStatements/Parameter.cs @@ -8,4 +8,4 @@ namespace RentADeveloper.DbConnectionPlus.SqlStatements; /// /// The name of the parameter. /// The value of the parameter. -internal record Parameter(String Name, Object? Value) : IInterpolatedSqlStatementFragment; +internal record Parameter(string Name, object? Value) : IInterpolatedSqlStatementFragment; diff --git a/src/DbConnectionPlus/ThrowHelper.cs b/src/DbConnectionPlus/ThrowHelper.cs index 7048eb8..c84b8b2 100644 --- a/src/DbConnectionPlus/ThrowHelper.cs +++ b/src/DbConnectionPlus/ThrowHelper.cs @@ -55,9 +55,9 @@ public static void ThrowDatabaseAdapterDoesNotSupportTemporaryTablesException(ID [MethodImpl(MethodImplOptions.NoInlining)] [DoesNotReturn] public static void ThrowDatabaseOperationAffectedUnexpectedNumberOfRowsException( - Int32 expectedNumberOfAffectedRows, - Int32 actualNumberOfAffectedRows, - Object entity + int expectedNumberOfAffectedRows, + int actualNumberOfAffectedRows, + object entity ) => throw new DbUpdateConcurrencyException( $"The database operation was expected to affect {expectedNumberOfAffectedRows} row(s), but actually " + diff --git a/tests/DbConnectionPlus.IntegrationTests/Assertions/EntityAssertions.cs b/tests/DbConnectionPlus.IntegrationTests/Assertions/EntityAssertions.cs index e8c1ac2..d3f854e 100644 --- a/tests/DbConnectionPlus.IntegrationTests/Assertions/EntityAssertions.cs +++ b/tests/DbConnectionPlus.IntegrationTests/Assertions/EntityAssertions.cs @@ -20,13 +20,13 @@ Entity entity // We need to use the ValueConverter here because each database provider handles the types a bit // differently. - ValueConverter.ConvertValueToType(dataRow["BooleanValue"]) + ValueConverter.ConvertValueToType(dataRow["BooleanValue"]) .Should().Be(entity.BooleanValue); - ValueConverter.ConvertValueToType(dataRow["ByteValue"]) + ValueConverter.ConvertValueToType(dataRow["ByteValue"]) .Should().Be(entity.ByteValue); - ValueConverter.ConvertValueToType(dataRow["CharValue"]) + ValueConverter.ConvertValueToType(dataRow["CharValue"]) .Should().Be(entity.CharValue); ValueConverter.ConvertValueToType(dataRow["DateOnlyValue"]) @@ -35,10 +35,10 @@ Entity entity ValueConverter.ConvertValueToType(dataRow["DateTimeValue"]) .Should().Be(entity.DateTimeValue); - ValueConverter.ConvertValueToType(dataRow["DecimalValue"]) + ValueConverter.ConvertValueToType(dataRow["DecimalValue"]) .Should().Be(entity.DecimalValue); - ValueConverter.ConvertValueToType(dataRow["DoubleValue"]) + ValueConverter.ConvertValueToType(dataRow["DoubleValue"]) .Should().Be(entity.DoubleValue); ValueConverter.ConvertValueToType(dataRow["EnumValue"]) @@ -47,22 +47,22 @@ Entity entity ValueConverter.ConvertValueToType(dataRow["GuidValue"]) .Should().Be(entity.GuidValue); - ValueConverter.ConvertValueToType(dataRow["Id"]) + ValueConverter.ConvertValueToType(dataRow["Id"]) .Should().Be(entity.Id); - ValueConverter.ConvertValueToType(dataRow["Int16Value"]) + ValueConverter.ConvertValueToType(dataRow["Int16Value"]) .Should().Be(entity.Int16Value); - ValueConverter.ConvertValueToType(dataRow["Int32Value"]) + ValueConverter.ConvertValueToType(dataRow["Int32Value"]) .Should().Be(entity.Int32Value); - ValueConverter.ConvertValueToType(dataRow["Int64Value"]) + ValueConverter.ConvertValueToType(dataRow["Int64Value"]) .Should().Be(entity.Int64Value); - ValueConverter.ConvertValueToType(dataRow["SingleValue"]) + ValueConverter.ConvertValueToType(dataRow["SingleValue"]) .Should().Be(entity.SingleValue); - ValueConverter.ConvertValueToType(dataRow["StringValue"]) + ValueConverter.ConvertValueToType(dataRow["StringValue"]) .Should().Be(entity.StringValue); ValueConverter.ConvertValueToType(dataRow["TimeOnlyValue"]) diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntitiesTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntitiesTests.cs index 06a5a13..638ad22 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntitiesTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntitiesTests.cs @@ -36,7 +36,7 @@ protected EntityManipulator_DeleteEntitiesTests() => [InlineData(false)] [InlineData(true)] public async Task DeleteEntities_CancellationToken_ShouldCancelOperationIfCancellationIsRequested( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -70,12 +70,12 @@ await Invoking(() => this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task DeleteEntities_ConcurrencyTokenMismatch_ShouldThrow(Boolean useAsyncApi) + public async Task DeleteEntities_ConcurrencyTokenMismatch_ShouldThrow(bool useAsyncApi) { var entitiesToDelete = this.CreateEntitiesInDb(5); var failingEntity = entitiesToDelete[^1]; - failingEntity.ConcurrencyToken_ = Generate.Single(); + failingEntity.ConcurrencyToken_ = Generate.Single(); var exception = (await Invoking(() => this.CallApi( useAsyncApi, @@ -112,7 +112,7 @@ public async Task DeleteEntities_ConcurrencyTokenMismatch_ShouldThrow(Boolean us [Theory] [InlineData(false)] [InlineData(true)] - public async Task DeleteEntities_Mapping_Attributes_ShouldUseAttributesMapping(Boolean useAsyncApi) + public async Task DeleteEntities_Mapping_Attributes_ShouldUseAttributesMapping(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(10); var entitiesToDelete = entities.Take(5).ToList(); @@ -142,7 +142,7 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task DeleteEntities_Mapping_FluentApi_ShouldUseFluentApiMapping(Boolean useAsyncApi) + public async Task DeleteEntities_Mapping_FluentApi_ShouldUseFluentApiMapping(bool useAsyncApi) { MappingTestEntityFluentApi.Configure(); @@ -174,7 +174,7 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public Task DeleteEntities_Mapping_MissingKeyProperty_ShouldThrow(Boolean useAsyncApi) + public Task DeleteEntities_Mapping_MissingKeyProperty_ShouldThrow(bool useAsyncApi) { var entityWithoutKeyProperty = new EntityWithoutKeyProperty(); @@ -196,7 +196,7 @@ public Task DeleteEntities_Mapping_MissingKeyProperty_ShouldThrow(Boolean useAsy [Theory] [InlineData(false)] [InlineData(true)] - public async Task DeleteEntities_Mapping_NoMapping_ShouldUseEntityTypeNameAndPropertyNames(Boolean useAsyncApi) + public async Task DeleteEntities_Mapping_NoMapping_ShouldUseEntityTypeNameAndPropertyNames(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(10); var entitiesToDelete = entities.Take(5).ToList(); @@ -226,12 +226,12 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task DeleteEntities_RowVersionMismatch_ShouldThrow(Boolean useAsyncApi) + public async Task DeleteEntities_RowVersionMismatch_ShouldThrow(bool useAsyncApi) { var entitiesToDelete = this.CreateEntitiesInDb(5); var failingEntity = entitiesToDelete[^1]; - failingEntity.RowVersion_ = Generate.Single(); + failingEntity.RowVersion_ = Generate.Single(); var exception = (await Invoking(() => this.CallApi( useAsyncApi, @@ -267,7 +267,7 @@ public async Task DeleteEntities_RowVersionMismatch_ShouldThrow(Boolean useAsync [Theory] [InlineData(false)] [InlineData(true)] - public async Task DeleteEntities_ShouldReturnNumberOfAffectedRows(Boolean useAsyncApi) + public async Task DeleteEntities_ShouldReturnNumberOfAffectedRows(bool useAsyncApi) { var entitiesToDelete = this.CreateEntitiesInDb(); @@ -293,7 +293,7 @@ public async Task DeleteEntities_ShouldReturnNumberOfAffectedRows(Boolean useAsy [Theory] [InlineData(false)] [InlineData(true)] - public async Task DeleteEntities_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task DeleteEntities_Transaction_ShouldUseTransaction(bool useAsyncApi) { var entitiesToDelete = this.CreateEntitiesInDb(); @@ -323,8 +323,8 @@ await this.CallApi( } } - private Task CallApi( - Boolean useAsyncApi, + private Task CallApi( + bool useAsyncApi, DbConnection connection, IEnumerable entities, DbTransaction? transaction = null, @@ -345,7 +345,7 @@ private Task CallApi( } catch (Exception ex) { - return Task.FromException(ex); + return Task.FromException(ex); } } diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntityTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntityTests.cs index f4003f1..bc7f272 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntityTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntityTests.cs @@ -35,7 +35,7 @@ protected EntityManipulator_DeleteEntityTests() => [Theory] [InlineData(false)] [InlineData(true)] - public async Task DeleteEntity_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(Boolean useAsyncApi) + public async Task DeleteEntity_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -64,10 +64,10 @@ await Invoking(() => this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task DeleteEntity_ConcurrencyTokenMismatch_ShouldThrow(Boolean useAsyncApi) + public async Task DeleteEntity_ConcurrencyTokenMismatch_ShouldThrow(bool useAsyncApi) { var entityToDelete = this.CreateEntityInDb(); - entityToDelete.ConcurrencyToken_ = Generate.Single(); + entityToDelete.ConcurrencyToken_ = Generate.Single(); var exception = (await Invoking(() => this.CallApi( useAsyncApi, @@ -97,7 +97,7 @@ public async Task DeleteEntity_ConcurrencyTokenMismatch_ShouldThrow(Boolean useA [Theory] [InlineData(false)] [InlineData(true)] - public async Task DeleteEntity_Mapping_Attributes_ShouldUseAttributesMapping(Boolean useAsyncApi) + public async Task DeleteEntity_Mapping_Attributes_ShouldUseAttributesMapping(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(2); var entityToDelete = entities[0]; @@ -121,7 +121,7 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task DeleteEntity_Mapping_FluentApi_ShouldUseFluentApiMapping(Boolean useAsyncApi) + public async Task DeleteEntity_Mapping_FluentApi_ShouldUseFluentApiMapping(bool useAsyncApi) { MappingTestEntityFluentApi.Configure(); @@ -147,7 +147,7 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public Task DeleteEntity_Mapping_MissingKeyProperty_ShouldThrow(Boolean useAsyncApi) + public Task DeleteEntity_Mapping_MissingKeyProperty_ShouldThrow(bool useAsyncApi) { var entityWithoutKeyProperty = new EntityWithoutKeyProperty(); @@ -169,7 +169,7 @@ public Task DeleteEntity_Mapping_MissingKeyProperty_ShouldThrow(Boolean useAsync [Theory] [InlineData(false)] [InlineData(true)] - public async Task DeleteEntity_Mapping_NoMapping_ShouldUseEntityTypeNameAndPropertyNames(Boolean useAsyncApi) + public async Task DeleteEntity_Mapping_NoMapping_ShouldUseEntityTypeNameAndPropertyNames(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(2); var entityToDelete = entities[0]; @@ -193,10 +193,10 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task DeleteEntity_RowVersionMismatch_ShouldThrow(Boolean useAsyncApi) + public async Task DeleteEntity_RowVersionMismatch_ShouldThrow(bool useAsyncApi) { var entityToDelete = this.CreateEntityInDb(); - entityToDelete.RowVersion_ = Generate.Single(); + entityToDelete.RowVersion_ = Generate.Single(); var exception = (await Invoking(() => this.CallApi( useAsyncApi, @@ -226,7 +226,7 @@ public async Task DeleteEntity_RowVersionMismatch_ShouldThrow(Boolean useAsyncAp [Theory] [InlineData(false)] [InlineData(true)] - public async Task DeleteEntity_ShouldReturnNumberOfAffectedRows(Boolean useAsyncApi) + public async Task DeleteEntity_ShouldReturnNumberOfAffectedRows(bool useAsyncApi) { var entityToDelete = this.CreateEntityInDb(); @@ -243,7 +243,7 @@ public async Task DeleteEntity_ShouldReturnNumberOfAffectedRows(Boolean useAsync [Theory] [InlineData(false)] [InlineData(true)] - public async Task DeleteEntity_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task DeleteEntity_Transaction_ShouldUseTransaction(bool useAsyncApi) { var entityToDelete = this.CreateEntityInDb(); @@ -267,8 +267,8 @@ await this.CallApi( .Should().BeTrue(); } - private Task CallApi( - Boolean useAsyncApi, + private Task CallApi( + bool useAsyncApi, DbConnection connection, TEntity entity, DbTransaction? transaction = null, @@ -289,7 +289,7 @@ private Task CallApi( } catch (Exception ex) { - return Task.FromException(ex); + return Task.FromException(ex); } } diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntitiesTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntitiesTests.cs index 185ec00..013bc04 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntitiesTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntitiesTests.cs @@ -35,7 +35,7 @@ protected EntityManipulator_InsertEntitiesTests() => [InlineData(false)] [InlineData(true)] public async Task InsertEntities_CancellationToken_ShouldCancelOperationIfCancellationIsRequested( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -64,7 +64,7 @@ await Invoking(() => [InlineData(false)] [InlineData(true)] public async Task InsertEntities_EnumSerializationModeIsIntegers_ShouldStoreEnumValuesAsIntegers( - Boolean useAsyncApi + bool useAsyncApi ) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Integers; @@ -79,17 +79,17 @@ await this.CallApi( TestContext.Current.CancellationToken ); - (await this.Connection.QueryAsync( + (await this.Connection.QueryAsync( $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsInteger")}", cancellationToken: TestContext.Current.CancellationToken ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities.Select(a => (Int32)a.Enum)); + .Should().BeEquivalentTo(entities.Select(a => (int)a.Enum)); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task InsertEntities_EnumSerializationModeIsStrings_ShouldStoreEnumValuesAsStrings(Boolean useAsyncApi) + public async Task InsertEntities_EnumSerializationModeIsStrings_ShouldStoreEnumValuesAsStrings(bool useAsyncApi) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Strings; @@ -103,7 +103,7 @@ await this.CallApi( TestContext.Current.CancellationToken ); - (await this.Connection.QueryAsync( + (await this.Connection.QueryAsync( $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsString")}", cancellationToken: TestContext.Current.CancellationToken ).ToListAsync(TestContext.Current.CancellationToken)) @@ -113,7 +113,7 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task InsertEntities_Mapping_Attributes_ShouldUseAttributesMapping(Boolean useAsyncApi) + public async Task InsertEntities_Mapping_Attributes_ShouldUseAttributesMapping(bool useAsyncApi) { var entities = Generate.Multiple(); entities.ForEach(a => @@ -135,7 +135,7 @@ await this.CallApi( this.Connection.Query($"SELECT * FROM {Q("MappingTestEntity")}") .Should().BeEquivalentTo( entities, - options => options.Using(context => context.Subject.Should().BeNull()) + options => options.Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -143,7 +143,7 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task InsertEntities_Mapping_FluentApi_ShouldUseFluentApiMapping(Boolean useAsyncApi) + public async Task InsertEntities_Mapping_FluentApi_ShouldUseFluentApiMapping(bool useAsyncApi) { MappingTestEntityFluentApi.Configure(); @@ -167,7 +167,7 @@ await this.CallApi( this.Connection.Query($"SELECT * FROM {Q("MappingTestEntity")}") .Should().BeEquivalentTo( entities, - options => options.Using(context => context.Subject.Should().BeNull()) + options => options.Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -175,7 +175,7 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task InsertEntities_Mapping_NoMapping_ShouldUseEntityTypeNameAndPropertyNames(Boolean useAsyncApi) + public async Task InsertEntities_Mapping_NoMapping_ShouldUseEntityTypeNameAndPropertyNames(bool useAsyncApi) { var entities = Generate.Multiple(); @@ -194,7 +194,7 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task InsertEntities_ShouldInsertEntities(Boolean useAsyncApi) + public async Task InsertEntities_ShouldInsertEntities(bool useAsyncApi) { var entities = Generate.Multiple(); @@ -217,7 +217,7 @@ public async Task InsertEntities_ShouldInsertEntities(Boolean useAsyncApi) [Theory] [InlineData(false)] [InlineData(true)] - public async Task InsertEntities_ShouldReturnNumberOfAffectedRows(Boolean useAsyncApi) + public async Task InsertEntities_ShouldReturnNumberOfAffectedRows(bool useAsyncApi) { var entities = Generate.Multiple(); @@ -243,7 +243,7 @@ public async Task InsertEntities_ShouldReturnNumberOfAffectedRows(Boolean useAsy [Theory] [InlineData(false)] [InlineData(true)] - public async Task InsertEntities_ShouldSupportDateTimeOffsetValues(Boolean useAsyncApi) + public async Task InsertEntities_ShouldSupportDateTimeOffsetValues(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); @@ -267,7 +267,7 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task InsertEntities_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task InsertEntities_Transaction_ShouldUseTransaction(bool useAsyncApi) { var entities = Generate.Multiple(); @@ -298,8 +298,8 @@ public async Task InsertEntities_Transaction_ShouldUseTransaction(Boolean useAsy } } - private Task CallApi( - Boolean useAsyncApi, + private Task CallApi( + bool useAsyncApi, DbConnection connection, IEnumerable entities, DbTransaction? transaction = null, @@ -320,7 +320,7 @@ private Task CallApi( } catch (Exception ex) { - return Task.FromException(ex); + return Task.FromException(ex); } } diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntityTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntityTests.cs index 87bde38..5f148e9 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntityTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntityTests.cs @@ -34,7 +34,7 @@ protected EntityManipulator_InsertEntityTests() => [Theory] [InlineData(false)] [InlineData(true)] - public async Task InsertEntity_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(Boolean useAsyncApi) + public async Task InsertEntity_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -58,7 +58,7 @@ await Invoking(() => [Theory] [InlineData(false)] [InlineData(true)] - public async Task InsertEntity_EnumSerializationModeIsIntegers_ShouldStoreEnumValuesAsIntegers(Boolean useAsyncApi) + public async Task InsertEntity_EnumSerializationModeIsIntegers_ShouldStoreEnumValuesAsIntegers(bool useAsyncApi) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Integers; @@ -66,17 +66,17 @@ public async Task InsertEntity_EnumSerializationModeIsIntegers_ShouldStoreEnumVa await this.CallApi(useAsyncApi, this.Connection, entity, null, TestContext.Current.CancellationToken); - (await this.Connection.QuerySingleAsync( + (await this.Connection.QuerySingleAsync( $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsInteger")}", cancellationToken: TestContext.Current.CancellationToken )) - .Should().Be((Int32)entity.Enum); + .Should().Be((int)entity.Enum); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task InsertEntity_EnumSerializationModeIsStrings_ShouldStoreEnumValuesAsStrings(Boolean useAsyncApi) + public async Task InsertEntity_EnumSerializationModeIsStrings_ShouldStoreEnumValuesAsStrings(bool useAsyncApi) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Strings; @@ -84,7 +84,7 @@ public async Task InsertEntity_EnumSerializationModeIsStrings_ShouldStoreEnumVal await this.CallApi(useAsyncApi, this.Connection, entity, null, TestContext.Current.CancellationToken); - (await this.Connection.QuerySingleAsync( + (await this.Connection.QuerySingleAsync( $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsString")}", cancellationToken: TestContext.Current.CancellationToken )) @@ -94,7 +94,7 @@ public async Task InsertEntity_EnumSerializationModeIsStrings_ShouldStoreEnumVal [Theory] [InlineData(false)] [InlineData(true)] - public async Task InsertEntity_Mapping_Attributes_ShouldUseAttributesMapping(Boolean useAsyncApi) + public async Task InsertEntity_Mapping_Attributes_ShouldUseAttributesMapping(bool useAsyncApi) { var entity = Generate.Single(); entity.Computed_ = 0; @@ -112,7 +112,7 @@ await this.CallApi( (await this.Connection.QueryFirstAsync($"SELECT * FROM {Q("MappingTestEntity")}")) .Should().BeEquivalentTo( entity, - options => options.Using(context => context.Subject.Should().BeNull()) + options => options.Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -120,7 +120,7 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task InsertEntity_Mapping_FluentApi_ShouldUseFluentApiMapping(Boolean useAsyncApi) + public async Task InsertEntity_Mapping_FluentApi_ShouldUseFluentApiMapping(bool useAsyncApi) { MappingTestEntityFluentApi.Configure(); @@ -140,7 +140,7 @@ await this.CallApi( (await this.Connection.QueryFirstAsync($"SELECT * FROM {Q("MappingTestEntity")}")) .Should().BeEquivalentTo( entity, - options => options.Using(context => context.Subject.Should().BeNull()) + options => options.Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -148,7 +148,7 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task InsertEntity_Mapping_NoMapping_ShouldUseEntityTypeNameAndPropertyNames(Boolean useAsyncApi) + public async Task InsertEntity_Mapping_NoMapping_ShouldUseEntityTypeNameAndPropertyNames(bool useAsyncApi) { var entity = Generate.Single(); @@ -167,7 +167,7 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task InsertEntity_ShouldInsertEntity(Boolean useAsyncApi) + public async Task InsertEntity_ShouldInsertEntity(bool useAsyncApi) { var entity = Generate.Single(); @@ -184,7 +184,7 @@ public async Task InsertEntity_ShouldInsertEntity(Boolean useAsyncApi) [Theory] [InlineData(false)] [InlineData(true)] - public async Task InsertEntity_ShouldReturnNumberOfAffectedRows(Boolean useAsyncApi) + public async Task InsertEntity_ShouldReturnNumberOfAffectedRows(bool useAsyncApi) { var entity = Generate.Single(); @@ -195,7 +195,7 @@ public async Task InsertEntity_ShouldReturnNumberOfAffectedRows(Boolean useAsync [Theory] [InlineData(false)] [InlineData(true)] - public async Task InsertEntity_ShouldSupportDateTimeOffsetValues(Boolean useAsyncApi) + public async Task InsertEntity_ShouldSupportDateTimeOffsetValues(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); @@ -213,7 +213,7 @@ public async Task InsertEntity_ShouldSupportDateTimeOffsetValues(Boolean useAsyn [Theory] [InlineData(false)] [InlineData(true)] - public async Task InsertEntity_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task InsertEntity_Transaction_ShouldUseTransaction(bool useAsyncApi) { var entity = Generate.Single(); @@ -238,8 +238,8 @@ public async Task InsertEntity_Transaction_ShouldUseTransaction(Boolean useAsync .Should().BeFalse(); } - private Task CallApi( - Boolean useAsyncApi, + private Task CallApi( + bool useAsyncApi, DbConnection connection, TEntity entity, DbTransaction? transaction = null, @@ -260,7 +260,7 @@ private Task CallApi( } catch (Exception ex) { - return Task.FromException(ex); + return Task.FromException(ex); } } diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntitiesTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntitiesTests.cs index 9a14194..7198578 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntitiesTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntitiesTests.cs @@ -36,7 +36,7 @@ protected EntityManipulator_UpdateEntitiesTests() => [InlineData(false)] [InlineData(true)] public async Task UpdateEntities_CancellationToken_ShouldCancelOperationIfCancellationIsRequested( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -65,13 +65,13 @@ await Invoking(() => [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntities_ConcurrencyTokenMismatch_ShouldThrow(Boolean useAsyncApi) + public async Task UpdateEntities_ConcurrencyTokenMismatch_ShouldThrow(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(); var updatedEntities = Generate.UpdateFor(entities); var failingEntity = updatedEntities[^1]; - failingEntity.ConcurrencyToken_ = Generate.Single(); + failingEntity.ConcurrencyToken_ = Generate.Single(); var exception = (await Invoking(() => this.CallApi( useAsyncApi, @@ -124,7 +124,7 @@ public async Task UpdateEntities_ConcurrencyTokenMismatch_ShouldThrow(Boolean us [InlineData(false)] [InlineData(true)] public async Task UpdateEntities_EnumSerializationModeIsIntegers_ShouldStoreEnumValuesAsIntegers( - Boolean useAsyncApi + bool useAsyncApi ) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Integers; @@ -139,11 +139,11 @@ await this.manipulator.InsertEntitiesAsync( ); // Make sure the enums are stored as integers: - (await this.Connection.QueryAsync( + (await this.Connection.QueryAsync( $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsInteger")}", cancellationToken: TestContext.Current.CancellationToken ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities.Select(a => (Int32)a.Enum)); + .Should().BeEquivalentTo(entities.Select(a => (int)a.Enum)); var updatedEntities = Generate.UpdateFor(entities); @@ -156,17 +156,17 @@ await this.CallApi( ); // Make sure the enums are stored as integers: - (await this.Connection.QueryAsync( + (await this.Connection.QueryAsync( $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsInteger")}", cancellationToken: TestContext.Current.CancellationToken ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(updatedEntities.Select(a => (Int32)a.Enum)); + .Should().BeEquivalentTo(updatedEntities.Select(a => (int)a.Enum)); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntities_EnumSerializationModeIsStrings_ShouldStoreEnumValuesAsStrings(Boolean useAsyncApi) + public async Task UpdateEntities_EnumSerializationModeIsStrings_ShouldStoreEnumValuesAsStrings(bool useAsyncApi) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Strings; @@ -180,7 +180,7 @@ await this.manipulator.InsertEntitiesAsync( ); // Make sure the enums are stored as strings: - (await this.Connection.QueryAsync( + (await this.Connection.QueryAsync( $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsString")}", cancellationToken: TestContext.Current.CancellationToken ).ToListAsync(TestContext.Current.CancellationToken)) @@ -197,7 +197,7 @@ await this.CallApi( ); // Make sure the enums are stored as strings: - (await this.Connection.QueryAsync( + (await this.Connection.QueryAsync( $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsString")}", cancellationToken: TestContext.Current.CancellationToken ).ToListAsync(TestContext.Current.CancellationToken)) @@ -207,7 +207,7 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntities_Mapping_Attributes_ShouldUseAttributesMapping(Boolean useAsyncApi) + public async Task UpdateEntities_Mapping_Attributes_ShouldUseAttributesMapping(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(); @@ -232,7 +232,7 @@ await this.CallApi( .Should().BeEquivalentTo( updatedEntities, options => - options.Using(context => context.Subject.Should().BeNull()) + options.Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -240,7 +240,7 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntities_Mapping_FluentApi_ShouldUseFluentApiMapping(Boolean useAsyncApi) + public async Task UpdateEntities_Mapping_FluentApi_ShouldUseFluentApiMapping(bool useAsyncApi) { MappingTestEntityFluentApi.Configure(); @@ -266,7 +266,7 @@ await this.CallApi( this.Connection.Query($"SELECT * FROM {Q("MappingTestEntity")}") .Should().BeEquivalentTo( updatedEntities, - options => options.Using(context => context.Subject.Should().BeNull()) + options => options.Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -274,7 +274,7 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public Task UpdateEntities_Mapping_MissingKeyProperty_ShouldThrow(Boolean useAsyncApi) + public Task UpdateEntities_Mapping_MissingKeyProperty_ShouldThrow(bool useAsyncApi) { var entityWithoutKeyProperty = new EntityWithoutKeyProperty(); @@ -296,7 +296,7 @@ public Task UpdateEntities_Mapping_MissingKeyProperty_ShouldThrow(Boolean useAsy [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntities_Mapping_NoMapping_ShouldUseEntityTypeNameAndPropertyNames(Boolean useAsyncApi) + public async Task UpdateEntities_Mapping_NoMapping_ShouldUseEntityTypeNameAndPropertyNames(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(); var updatedEntities = Generate.UpdateFor(entities); @@ -316,13 +316,13 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntities_RowVersionMismatch_ShouldThrow(Boolean useAsyncApi) + public async Task UpdateEntities_RowVersionMismatch_ShouldThrow(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(); var updatedEntities = Generate.UpdateFor(entities); var failingEntity = updatedEntities[^1]; - failingEntity.RowVersion_ = Generate.Single(); + failingEntity.RowVersion_ = Generate.Single(); var exception = (await Invoking(() => this.CallApi( useAsyncApi, @@ -374,7 +374,7 @@ public async Task UpdateEntities_RowVersionMismatch_ShouldThrow(Boolean useAsync [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntities_ShouldReturnNumberOfAffectedRows(Boolean useAsyncApi) + public async Task UpdateEntities_ShouldReturnNumberOfAffectedRows(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(); var updatedEntities = Generate.UpdateFor(entities); @@ -401,7 +401,7 @@ public async Task UpdateEntities_ShouldReturnNumberOfAffectedRows(Boolean useAsy [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntities_ShouldSupportDateTimeOffsetValues(Boolean useAsyncApi) + public async Task UpdateEntities_ShouldSupportDateTimeOffsetValues(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); @@ -426,7 +426,7 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntities_ShouldUpdateEntities(Boolean useAsyncApi) + public async Task UpdateEntities_ShouldUpdateEntities(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(); var updatedEntities = Generate.UpdateFor(entities); @@ -450,7 +450,7 @@ public async Task UpdateEntities_ShouldUpdateEntities(Boolean useAsyncApi) [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntities_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task UpdateEntities_Transaction_ShouldUseTransaction(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(); @@ -479,8 +479,8 @@ public async Task UpdateEntities_Transaction_ShouldUseTransaction(Boolean useAsy .Should().BeEquivalentTo(entities); } - private Task CallApi( - Boolean useAsyncApi, + private Task CallApi( + bool useAsyncApi, DbConnection connection, IEnumerable entities, DbTransaction? transaction = null, @@ -501,7 +501,7 @@ private Task CallApi( } catch (Exception ex) { - return Task.FromException(ex); + return Task.FromException(ex); } } diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntityTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntityTests.cs index 609177c..c5ff9ad 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntityTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntityTests.cs @@ -35,7 +35,7 @@ protected EntityManipulator_UpdateEntityTests() => [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntity_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(Boolean useAsyncApi) + public async Task UpdateEntity_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -63,12 +63,12 @@ await Invoking(() => [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntity_ConcurrencyTokenMismatch_ShouldThrow(Boolean useAsyncApi) + public async Task UpdateEntity_ConcurrencyTokenMismatch_ShouldThrow(bool useAsyncApi) { var entity = this.CreateEntityInDb(); var updatedEntity = Generate.UpdateFor(entity); - updatedEntity.ConcurrencyToken_ = Generate.Single(); + updatedEntity.ConcurrencyToken_ = Generate.Single(); var exception = (await Invoking(() => this.CallApi( useAsyncApi, @@ -106,7 +106,7 @@ public async Task UpdateEntity_ConcurrencyTokenMismatch_ShouldThrow(Boolean useA [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntity_EnumSerializationModeIsIntegers_ShouldStoreEnumValuesAsIntegers(Boolean useAsyncApi) + public async Task UpdateEntity_EnumSerializationModeIsIntegers_ShouldStoreEnumValuesAsIntegers(bool useAsyncApi) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Integers; @@ -115,11 +115,11 @@ public async Task UpdateEntity_EnumSerializationModeIsIntegers_ShouldStoreEnumVa await this.manipulator.InsertEntityAsync(this.Connection, entity, null, TestContext.Current.CancellationToken); // Make sure the enum is stored as integer: - (await this.Connection.QuerySingleAsync( + (await this.Connection.QuerySingleAsync( $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsInteger")}", cancellationToken: TestContext.Current.CancellationToken )) - .Should().Be((Int32)entity.Enum); + .Should().Be((int)entity.Enum); var updatedEntity = Generate.UpdateFor(entity); @@ -132,17 +132,17 @@ await this.CallApi( ); // Make sure the enum is stored as integer: - (await this.Connection.QuerySingleAsync( + (await this.Connection.QuerySingleAsync( $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsInteger")}", cancellationToken: TestContext.Current.CancellationToken )) - .Should().Be((Int32)updatedEntity.Enum); + .Should().Be((int)updatedEntity.Enum); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntity_EnumSerializationModeIsStrings_ShouldStoreEnumValuesAsStrings(Boolean useAsyncApi) + public async Task UpdateEntity_EnumSerializationModeIsStrings_ShouldStoreEnumValuesAsStrings(bool useAsyncApi) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Strings; @@ -151,7 +151,7 @@ public async Task UpdateEntity_EnumSerializationModeIsStrings_ShouldStoreEnumVal await this.manipulator.InsertEntityAsync(this.Connection, entity, null, TestContext.Current.CancellationToken); // Make sure the enum is stored as string: - (await this.Connection.QuerySingleAsync( + (await this.Connection.QuerySingleAsync( $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsString")}", cancellationToken: TestContext.Current.CancellationToken )) @@ -168,7 +168,7 @@ await this.CallApi( ); // Make sure the enum is stored as string: - (await this.Connection.QuerySingleAsync( + (await this.Connection.QuerySingleAsync( $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsString")}", cancellationToken: TestContext.Current.CancellationToken )) @@ -178,7 +178,7 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntity_Mapping_Attributes_ShouldUseAttributesMapping(Boolean useAsyncApi) + public async Task UpdateEntity_Mapping_Attributes_ShouldUseAttributesMapping(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -198,7 +198,7 @@ await this.CallApi( (await this.Connection.QueryFirstAsync($"SELECT * FROM {Q("MappingTestEntity")}")) .Should().BeEquivalentTo( updatedEntity, - options => options.Using(context => context.Subject.Should().BeNull()) + options => options.Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -206,7 +206,7 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntity_Mapping_FluentApi_ShouldUseFluentApiMapping(Boolean useAsyncApi) + public async Task UpdateEntity_Mapping_FluentApi_ShouldUseFluentApiMapping(bool useAsyncApi) { MappingTestEntityFluentApi.Configure(); @@ -228,7 +228,7 @@ await this.CallApi( (await this.Connection.QueryFirstAsync($"SELECT * FROM {Q("MappingTestEntity")}")) .Should().BeEquivalentTo( updatedEntity, - options => options.Using(context => context.Subject.Should().BeNull()) + options => options.Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -236,7 +236,7 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public Task UpdateEntity_Mapping_MissingKeyProperty_ShouldThrow(Boolean useAsyncApi) + public Task UpdateEntity_Mapping_MissingKeyProperty_ShouldThrow(bool useAsyncApi) { var entityWithoutKeyProperty = new EntityWithoutKeyProperty(); @@ -258,7 +258,7 @@ public Task UpdateEntity_Mapping_MissingKeyProperty_ShouldThrow(Boolean useAsync [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntity_Mapping_NoMapping_ShouldUseEntityTypeNameAndPropertyNames(Boolean useAsyncApi) + public async Task UpdateEntity_Mapping_NoMapping_ShouldUseEntityTypeNameAndPropertyNames(bool useAsyncApi) { var entity = this.CreateEntityInDb(); var updatedEntity = Generate.UpdateFor(entity); @@ -278,12 +278,12 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntity_RowVersionMismatch_ShouldThrow(Boolean useAsyncApi) + public async Task UpdateEntity_RowVersionMismatch_ShouldThrow(bool useAsyncApi) { var entity = this.CreateEntityInDb(); var updatedEntity = Generate.UpdateFor(entity); - updatedEntity.RowVersion_ = Generate.Single(); + updatedEntity.RowVersion_ = Generate.Single(); var exception = (await Invoking(() => this.CallApi( useAsyncApi, @@ -321,7 +321,7 @@ public async Task UpdateEntity_RowVersionMismatch_ShouldThrow(Boolean useAsyncAp [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntity_ShouldReturnNumberOfAffectedRows(Boolean useAsyncApi) + public async Task UpdateEntity_ShouldReturnNumberOfAffectedRows(bool useAsyncApi) { var entity = this.CreateEntityInDb(); var updatedEntity = Generate.UpdateFor(entity); @@ -339,7 +339,7 @@ public async Task UpdateEntity_ShouldReturnNumberOfAffectedRows(Boolean useAsync [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntity_ShouldSupportDateTimeOffsetValues(Boolean useAsyncApi) + public async Task UpdateEntity_ShouldSupportDateTimeOffsetValues(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); @@ -364,7 +364,7 @@ await this.CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntity_ShouldUpdateEntity(Boolean useAsyncApi) + public async Task UpdateEntity_ShouldUpdateEntity(bool useAsyncApi) { var entity = this.CreateEntityInDb(); var updatedEntity = Generate.UpdateFor(entity); @@ -388,7 +388,7 @@ public async Task UpdateEntity_ShouldUpdateEntity(Boolean useAsyncApi) [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntity_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task UpdateEntity_Transaction_ShouldUseTransaction(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -415,8 +415,8 @@ public async Task UpdateEntity_Transaction_ShouldUseTransaction(Boolean useAsync .Should().BeEquivalentTo(entity); } - private Task CallApi( - Boolean useAsyncApi, + private Task CallApi( + bool useAsyncApi, DbConnection connection, TEntity entity, DbTransaction? transaction = null, @@ -437,7 +437,7 @@ private Task CallApi( } catch (Exception ex) { - return Task.FromException(ex); + return Task.FromException(ex); } } diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs index 9876357..5b87f89 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs @@ -10,7 +10,7 @@ public class OracleDatabaseAdapterTests : IntegrationTestsBase( + var prefix = this.Connection.ExecuteScalar( "SELECT VALUE FROM v$parameter WHERE NAME = 'private_temp_table_prefix'" ); diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/TemporaryTableBuilderTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/TemporaryTableBuilderTests.cs index efb49f7..91fa738 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/TemporaryTableBuilderTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/TemporaryTableBuilderTests.cs @@ -37,7 +37,7 @@ protected TemporaryTableBuilderTests() => [InlineData(false)] [InlineData(true)] public async Task BuildTemporaryTable_ComplexObjects_DateTimeOffsetProperty_ShouldSupportDateTimeOffset( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); @@ -66,7 +66,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task BuildTemporaryTable_ComplexObjects_EnumSerializationModeIsIntegers_ShouldStoreEnumValuesAsIntegers( - Boolean useAsyncApi + bool useAsyncApi ) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Integers; @@ -95,14 +95,14 @@ Boolean useAsyncApi ); reader.GetFieldType(0) - .Should().BeAnyOf(typeof(Int32), typeof(Int64)); + .Should().BeAnyOf(typeof(int), typeof(long)); foreach (var entity in entities) { await reader.ReadAsync(TestContext.Current.CancellationToken); reader.GetInt32(0) - .Should().Be((Int32)entity.Enum); + .Should().Be((int)entity.Enum); } } @@ -111,7 +111,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task BuildTemporaryTable_ComplexObjects_EnumSerializationModeIsStrings_ShouldStoreEnumValuesAsStrings( - Boolean useAsyncApi + bool useAsyncApi ) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Strings; @@ -140,7 +140,7 @@ Boolean useAsyncApi ); reader.GetFieldType(0) - .Should().Be(typeof(String)); + .Should().Be(typeof(string)); foreach (var entity in entities) { @@ -156,7 +156,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task BuildTemporaryTable_ComplexObjects_EnumSerializationModeIsStrings_ShouldUseCollationOfDatabaseForEnumColumns( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipWhen(this.TestDatabaseProvider.TemporaryTableTextColumnInheritsCollationFromDatabase, ""); @@ -183,7 +183,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task BuildTemporaryTable_ComplexObjects_Mapping_Attributes_ShouldUseAttributesMapping( - Boolean useAsyncApi + bool useAsyncApi ) { var entities = Generate.Multiple(); @@ -212,7 +212,7 @@ Boolean useAsyncApi this.Connection.Query($"SELECT * FROM {QT("Objects")}") .Should().BeEquivalentTo( entities, - options => options.Using(context => context.Subject.Should().BeNull()) + options => options.Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -221,7 +221,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task BuildTemporaryTable_ComplexObjects_Mapping_FluentApi_ShouldUseFluentApiMapping( - Boolean useAsyncApi + bool useAsyncApi ) { MappingTestEntityFluentApi.Configure(); @@ -252,7 +252,7 @@ Boolean useAsyncApi this.Connection.Query($"SELECT * FROM {QT("Objects")}") .Should().BeEquivalentTo( entities, - options => options.Using(context => context.Subject.Should().BeNull()) + options => options.Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -261,7 +261,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task BuildTemporaryTable_ComplexObjects_NoMapping_ShouldUseEntityTypeNameAndPropertyNames( - Boolean useAsyncApi + bool useAsyncApi ) { var entities = Generate.Multiple(); @@ -283,7 +283,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildTemporaryTable_ComplexObjects_ShouldCreateMultiColumnTable(Boolean useAsyncApi) + public async Task BuildTemporaryTable_ComplexObjects_ShouldCreateMultiColumnTable(bool useAsyncApi) { var items = Generate.Multiple(); @@ -307,7 +307,7 @@ public async Task BuildTemporaryTable_ComplexObjects_ShouldCreateMultiColumnTabl [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildTemporaryTable_ComplexObjects_ShouldUseCollationOfDatabaseForTextColumns(Boolean useAsyncApi) + public async Task BuildTemporaryTable_ComplexObjects_ShouldUseCollationOfDatabaseForTextColumns(bool useAsyncApi) { Assert.SkipWhen(this.TestDatabaseProvider.TemporaryTableTextColumnInheritsCollationFromDatabase, ""); @@ -330,7 +330,7 @@ public async Task BuildTemporaryTable_ComplexObjects_ShouldUseCollationOfDatabas [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildTemporaryTable_ComplexObjects_WithNullables_ShouldHandleNullValues(Boolean useAsyncApi) + public async Task BuildTemporaryTable_ComplexObjects_WithNullables_ShouldHandleNullValues(bool useAsyncApi) { var itemsWithNulls = new List { new() }; @@ -355,7 +355,7 @@ public async Task BuildTemporaryTable_ComplexObjects_WithNullables_ShouldHandleN [InlineData(false)] [InlineData(true)] public async Task BuildTemporaryTable_ScalarValues_DateTimeOffsetValues_ShouldSupportDateTimeOffset( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); @@ -384,7 +384,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task BuildTemporaryTable_ScalarValues_EnumSerializationModeIsIntegers_ShouldStoreEnumValuesAsIntegers( - Boolean useAsyncApi + bool useAsyncApi ) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Integers; @@ -413,14 +413,14 @@ Boolean useAsyncApi ); reader.GetFieldType(0) - .Should().BeAnyOf(typeof(Int32), typeof(Int64)); + .Should().BeAnyOf(typeof(int), typeof(long)); foreach (var value in values) { await reader.ReadAsync(TestContext.Current.CancellationToken); reader.GetInt32(0) - .Should().Be((Int32)value); + .Should().Be((int)value); } } @@ -429,7 +429,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task BuildTemporaryTable_ScalarValues_EnumSerializationModeIsStrings_ShouldStoreEnumValuesAsStrings( - Boolean useAsyncApi + bool useAsyncApi ) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Strings; @@ -458,7 +458,7 @@ Boolean useAsyncApi ); reader.GetFieldType(0) - .Should().Be(typeof(String)); + .Should().Be(typeof(string)); foreach (var value in values) { @@ -474,7 +474,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task BuildTemporaryTable_ScalarValues_EnumSerializationModeIsStrings_ShouldUseCollationOfDatabaseForEnumColumns( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipWhen(this.TestDatabaseProvider.TemporaryTableTextColumnInheritsCollationFromDatabase, ""); @@ -501,7 +501,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task - BuildTemporaryTable_ScalarValues_NullableEnumValues_ShouldFillTableWithEnumsAndNulls(Boolean useAsyncApi) + BuildTemporaryTable_ScalarValues_NullableEnumValues_ShouldFillTableWithEnumsAndNulls(bool useAsyncApi) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Strings; @@ -527,9 +527,9 @@ public async Task [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildTemporaryTable_ScalarValues_ShouldCreateSingleColumnTable(Boolean useAsyncApi) + public async Task BuildTemporaryTable_ScalarValues_ShouldCreateSingleColumnTable(bool useAsyncApi) { - var values = Generate.Multiple(); + var values = Generate.Multiple(); await using var tableDisposer = await this.CallApi( useAsyncApi, @@ -537,11 +537,11 @@ public async Task BuildTemporaryTable_ScalarValues_ShouldCreateSingleColumnTable null, "Values", values, - typeof(Int32), + typeof(int), TestContext.Current.CancellationToken ); - (await this.Connection.QueryAsync( + (await this.Connection.QueryAsync( $"SELECT {Q("Value")} FROM {QT("Values")}", cancellationToken: TestContext.Current.CancellationToken ).ToListAsync(TestContext.Current.CancellationToken)) @@ -551,7 +551,7 @@ public async Task BuildTemporaryTable_ScalarValues_ShouldCreateSingleColumnTable [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildTemporaryTable_ScalarValues_ShouldUseCollationOfDatabaseForTextColumns(Boolean useAsyncApi) + public async Task BuildTemporaryTable_ScalarValues_ShouldUseCollationOfDatabaseForTextColumns(bool useAsyncApi) { Assert.SkipWhen(this.TestDatabaseProvider.TemporaryTableTextColumnInheritsCollationFromDatabase, ""); @@ -560,8 +560,8 @@ public async Task BuildTemporaryTable_ScalarValues_ShouldUseCollationOfDatabaseF this.Connection, null, "Values", - Generate.Multiple(), - typeof(String), + Generate.Multiple(), + typeof(string), TestContext.Current.CancellationToken ); @@ -574,9 +574,9 @@ public async Task BuildTemporaryTable_ScalarValues_ShouldUseCollationOfDatabaseF [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildTemporaryTable_ScalarValuesWithNullValues_ShouldHandleNullValues(Boolean useAsyncApi) + public async Task BuildTemporaryTable_ScalarValuesWithNullValues_ShouldHandleNullValues(bool useAsyncApi) { - var values = Generate.MultipleNullable(); + var values = Generate.MultipleNullable(); await using var tableDisposer = await this.CallApi( useAsyncApi, @@ -584,11 +584,11 @@ public async Task BuildTemporaryTable_ScalarValuesWithNullValues_ShouldHandleNul null, "NullValues", values, - typeof(Int32?), + typeof(int?), TestContext.Current.CancellationToken ); - (await this.Connection.QueryAsync( + (await this.Connection.QueryAsync( $"SELECT {Q("Value")} FROM {QT("NullValues")}", cancellationToken: TestContext.Current.CancellationToken ).ToListAsync(TestContext.Current.CancellationToken)) @@ -598,15 +598,15 @@ public async Task BuildTemporaryTable_ScalarValuesWithNullValues_ShouldHandleNul [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildTemporaryTable_ShouldReturnDisposerThatDropsTableAsync(Boolean useAsyncApi) + public async Task BuildTemporaryTable_ShouldReturnDisposerThatDropsTableAsync(bool useAsyncApi) { var disposer = await this.CallApi( useAsyncApi, this.Connection, null, "Values", - Generate.Multiple(), - typeof(Int32), + Generate.Multiple(), + typeof(int), TestContext.Current.CancellationToken ); @@ -620,10 +620,10 @@ public async Task BuildTemporaryTable_ShouldReturnDisposerThatDropsTableAsync(Bo } private Task CallApi( - Boolean useAsyncApi, + bool useAsyncApi, DbConnection connection, DbTransaction? transaction, - String name, + string name, IEnumerable values, Type valuesType, CancellationToken cancellationToken = default diff --git a/tests/DbConnectionPlus.IntegrationTests/DbCommands/DbCommandBuilderTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbCommands/DbCommandBuilderTests.cs index 243ad8d..5e9eaba 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbCommands/DbCommandBuilderTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbCommands/DbCommandBuilderTests.cs @@ -30,7 +30,7 @@ public abstract class DbCommandBuilderTests : Integration [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_ShouldCreateTemporaryTables(Boolean useAsyncApi) + public async Task BuildDbCommand_ShouldCreateTemporaryTables(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -64,7 +64,7 @@ SELECT Value this.ExistsTemporaryTableInDb(temporaryTables[1].Name) .Should().BeTrue(); - (await this.Connection.QueryAsync($"SELECT {Q("Value")} FROM {QT(temporaryTables[0].Name)}") + (await this.Connection.QueryAsync($"SELECT {Q("Value")} FROM {QT(temporaryTables[0].Name)}") .ToListAsync(TestContext.Current.CancellationToken)) .Should().BeEquivalentTo(entityIds); @@ -76,7 +76,7 @@ SELECT Value [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_ShouldReturnDisposerForCommandWhichDisposesTemporaryTables(Boolean useAsyncApi) + public async Task BuildDbCommand_ShouldReturnDisposerForCommandWhichDisposesTemporaryTables(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -115,7 +115,7 @@ SELECT Value [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_ShouldSetCommandTimeout(Boolean useAsyncApi) + public async Task BuildDbCommand_ShouldSetCommandTimeout(bool useAsyncApi) { var timeout = Generate.Single(); @@ -129,13 +129,13 @@ public async Task BuildDbCommand_ShouldSetCommandTimeout(Boolean useAsyncApi) ); command.CommandTimeout - .Should().Be((Int32)timeout.TotalSeconds); + .Should().Be((int)timeout.TotalSeconds); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_ShouldSetCommandType(Boolean useAsyncApi) + public async Task BuildDbCommand_ShouldSetCommandType(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsStoredProcedures, ""); @@ -154,7 +154,7 @@ public async Task BuildDbCommand_ShouldSetCommandType(Boolean useAsyncApi) [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_ShouldSetConnection(Boolean useAsyncApi) + public async Task BuildDbCommand_ShouldSetConnection(bool useAsyncApi) { var (command, _) = await CallApi(useAsyncApi, "SELECT 1", this.DatabaseAdapter, this.Connection); @@ -166,11 +166,11 @@ public async Task BuildDbCommand_ShouldSetConnection(Boolean useAsyncApi) [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_ShouldSetParameters(Boolean useAsyncApi) + public async Task BuildDbCommand_ShouldSetParameters(bool useAsyncApi) { var entityId = Generate.Id(); var dateTimeValue = DateTime.UtcNow; - var stringValue = Generate.Single(); + var stringValue = Generate.Single(); var (command, _) = await CallApi( useAsyncApi, @@ -212,7 +212,7 @@ FROM Entity [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_ShouldSetTransaction(Boolean useAsyncApi) + public async Task BuildDbCommand_ShouldSetTransaction(bool useAsyncApi) { await using var transaction = await this.Connection.BeginTransactionAsync(); @@ -231,7 +231,7 @@ public async Task BuildDbCommand_ShouldSetTransaction(Boolean useAsyncApi) [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_ShouldUseCancellationToken(Boolean useAsyncApi) + public async Task BuildDbCommand_ShouldUseCancellationToken(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -256,7 +256,7 @@ public async Task BuildDbCommand_ShouldUseCancellationToken(Boolean useAsyncApi) } private static Task<(DbCommand, DbCommandDisposer)> CallApi( - Boolean useAsyncApi, + bool useAsyncApi, InterpolatedSqlStatement statement, IDatabaseAdapter databaseAdapter, DbConnection connection, diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteNonQueryTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteNonQueryTests.cs index 8c07bea..f93e6a1 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteNonQueryTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteNonQueryTests.cs @@ -30,7 +30,7 @@ public abstract class [InlineData(false)] [InlineData(true)] public async Task ExecuteNonQuery_CancellationToken_ShouldCancelOperationIfCancellationIsRequested( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -59,7 +59,7 @@ await Invoking(() => CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteNonQuery_CommandType_ShouldPassUseCommandType(Boolean useAsyncApi) + public async Task ExecuteNonQuery_CommandType_ShouldPassUseCommandType(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsStoredProcedures, ""); @@ -81,7 +81,7 @@ await CallApi( [InlineData(false)] [InlineData(true)] public async Task ExecuteNonQuery_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -120,7 +120,7 @@ SELECT 1 [InlineData(true)] public async Task ExecuteNonQuery_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -160,7 +160,7 @@ SELECT 1 [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteNonQuery_InterpolatedParameter_ShouldPassInterpolatedParameter(Boolean useAsyncApi) + public async Task ExecuteNonQuery_InterpolatedParameter_ShouldPassInterpolatedParameter(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -178,7 +178,7 @@ await CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteNonQuery_Parameter_ShouldPassParameter(Boolean useAsyncApi) + public async Task ExecuteNonQuery_Parameter_ShouldPassParameter(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -202,7 +202,7 @@ await CallApi( [InlineData(false)] [InlineData(true)] public async Task ExecuteNonQuery_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -236,7 +236,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task ExecuteNonQuery_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -271,7 +271,7 @@ await CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteNonQuery_ShouldReturnNumberOfAffectedRows(Boolean useAsyncApi) + public async Task ExecuteNonQuery_ShouldReturnNumberOfAffectedRows(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -295,7 +295,7 @@ public async Task ExecuteNonQuery_ShouldReturnNumberOfAffectedRows(Boolean useAs [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteNonQuery_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task ExecuteNonQuery_Transaction_ShouldUseTransaction(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -319,8 +319,8 @@ await CallApi( .Should().BeTrue(); } - private static Task CallApi( - Boolean useAsyncApi, + private static Task CallApi( + bool useAsyncApi, DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, @@ -348,7 +348,7 @@ private static Task CallApi( } catch (Exception ex) { - return Task.FromException(ex); + return Task.FromException(ex); } } } diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteReaderTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteReaderTests.cs index 0399f4f..354338f 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteReaderTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteReaderTests.cs @@ -30,7 +30,7 @@ public abstract class [InlineData(false)] [InlineData(true)] public async Task ExecuteReader_CancellationToken_ShouldCancelOperationIfCancellationIsRequested( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -56,7 +56,7 @@ await Invoking(async () => [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteReader_CommandBehavior_ShouldUseCommandBehavior(Boolean useAsyncApi) + public async Task ExecuteReader_CommandBehavior_ShouldUseCommandBehavior(bool useAsyncApi) { var reader = await CallApi( useAsyncApi, @@ -75,7 +75,7 @@ public async Task ExecuteReader_CommandBehavior_ShouldUseCommandBehavior(Boolean [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteReader_CommandType_ShouldUseCommandType(Boolean useAsyncApi) + public async Task ExecuteReader_CommandType_ShouldUseCommandType(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsStoredProceduresReturningResultSet, ""); @@ -106,7 +106,7 @@ public async Task ExecuteReader_CommandType_ShouldUseCommandType(Boolean useAsyn [InlineData(false)] [InlineData(true)] public async Task - ExecuteReader_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterDataReaderDisposal(Boolean useAsyncApi) + ExecuteReader_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterDataReaderDisposal(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -142,7 +142,7 @@ public async Task [InlineData(true)] public async Task ExecuteReader_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -178,7 +178,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteReader_InterpolatedParameter_ShouldPassInterpolatedParameter(Boolean useAsyncApi) + public async Task ExecuteReader_InterpolatedParameter_ShouldPassInterpolatedParameter(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -199,7 +199,7 @@ public async Task ExecuteReader_InterpolatedParameter_ShouldPassInterpolatedPara [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteReader_Parameter_ShouldPassParameter(Boolean useAsyncApi) + public async Task ExecuteReader_Parameter_ShouldPassParameter(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -226,7 +226,7 @@ public async Task ExecuteReader_Parameter_ShouldPassParameter(Boolean useAsyncAp [InlineData(false)] [InlineData(true)] public async Task ExecuteReader_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterDataReaderDisposal( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -261,7 +261,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task ExecuteReader_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -288,7 +288,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteReader_ShouldReturnDataReaderForQueryResult(Boolean useAsyncApi) + public async Task ExecuteReader_ShouldReturnDataReaderForQueryResult(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(); @@ -318,7 +318,7 @@ public async Task ExecuteReader_ShouldReturnDataReaderForQueryResult(Boolean use [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteReader_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task ExecuteReader_Transaction_ShouldUseTransaction(bool useAsyncApi) { await using (var transaction = await this.Connection.BeginTransactionAsync()) { @@ -362,7 +362,7 @@ public async Task ExecuteReader_Transaction_ShouldUseTransaction(Boolean useAsyn } private static Task CallApi( - Boolean useAsyncApi, + bool useAsyncApi, DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteScalarTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteScalarTests.cs index 8d7baa5..93e907f 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteScalarTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteScalarTests.cs @@ -30,7 +30,7 @@ public abstract class [InlineData(false)] [InlineData(true)] public async Task ExecuteScalar_CancellationToken_ShouldCancelOperationIfCancellationIsRequested( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -40,7 +40,7 @@ Boolean useAsyncApi this.DelayNextDbCommand = true; await Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT 1", @@ -54,9 +54,9 @@ await Invoking(() => [Theory] [InlineData(false)] [InlineData(true)] - public Task ExecuteScalar_ColumnValueCannotBeConvertedToTargetType_ShouldThrow(Boolean useAsyncApi) => + public Task ExecuteScalar_ColumnValueCannotBeConvertedToTargetType_ShouldThrow(bool useAsyncApi) => Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT 'A'", @@ -66,19 +66,19 @@ public Task ExecuteScalar_ColumnValueCannotBeConvertedToTargetType_ShouldThrow(B .Should().ThrowAsync() .WithMessage( "The first column of the first row in the result set returned by the SQL statement contains the " + - $"value 'A' ({typeof(String)}), which could not be converted to the type {typeof(Int32)}.*" + $"value 'A' ({typeof(string)}), which could not be converted to the type {typeof(int)}.*" ); [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteScalar_CommandType_ShouldUseCommandType(Boolean useAsyncApi) + public async Task ExecuteScalar_CommandType_ShouldUseCommandType(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsStoredProceduresReturningResultSet, ""); var entity = this.CreateEntityInDb(); - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, "GetFirstEntityId", @@ -92,7 +92,7 @@ public async Task ExecuteScalar_CommandType_ShouldUseCommandType(Boolean useAsyn [InlineData(false)] [InlineData(true)] public async Task ExecuteScalar_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -106,7 +106,7 @@ Boolean useAsyncApi var temporaryTableName = statement.TemporaryTables[0].Name; - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, statement, @@ -123,14 +123,14 @@ Boolean useAsyncApi [InlineData(true)] public async Task ExecuteScalar_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entities = Generate.Multiple(1); - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, $""" @@ -145,11 +145,11 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteScalar_InterpolatedParameter_ShouldPassInterpolatedParameter(Boolean useAsyncApi) + public async Task ExecuteScalar_InterpolatedParameter_ShouldPassInterpolatedParameter(bool useAsyncApi) { var entity = this.CreateEntityInDb(); - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("StringValue")} FROM {Q("Entity")} WHERE {Q("Id")} = {Parameter(entity.Id)}", @@ -161,9 +161,9 @@ public async Task ExecuteScalar_InterpolatedParameter_ShouldPassInterpolatedPara [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteScalar_NoResultSet_ShouldReturnDefault(Boolean useAsyncApi) + public async Task ExecuteScalar_NoResultSet_ShouldReturnDefault(bool useAsyncApi) { - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, "SELECT 1 WHERE 0 = 1", @@ -171,7 +171,7 @@ public async Task ExecuteScalar_NoResultSet_ShouldReturnDefault(Boolean useAsync )) .Should().BeNull(); - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, "SELECT 1 WHERE 0 = 1", @@ -183,7 +183,7 @@ public async Task ExecuteScalar_NoResultSet_ShouldReturnDefault(Boolean useAsync [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteScalar_Parameter_ShouldPassParameter(Boolean useAsyncApi) + public async Task ExecuteScalar_Parameter_ShouldPassParameter(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -192,7 +192,7 @@ public async Task ExecuteScalar_Parameter_ShouldPassParameter(Boolean useAsyncAp ("Id", entity.Id) ); - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, statement, @@ -205,7 +205,7 @@ public async Task ExecuteScalar_Parameter_ShouldPassParameter(Boolean useAsyncAp [InlineData(false)] [InlineData(true)] public async Task ExecuteScalar_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -216,7 +216,7 @@ Boolean useAsyncApi var temporaryTableName = statement.TemporaryTables[0].Name; - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, statement, @@ -233,14 +233,14 @@ Boolean useAsyncApi [InlineData(true)] public async Task ExecuteScalar_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entityIds = Generate.Ids(1); - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("Value")} FROM {TemporaryTable(entityIds)}", @@ -252,7 +252,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteScalar_ShouldSupportDateTimeOffsetValues(Boolean useAsyncApi) + public async Task ExecuteScalar_ShouldSupportDateTimeOffsetValues(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); @@ -274,7 +274,7 @@ public async Task ExecuteScalar_ShouldSupportDateTimeOffsetValues(Boolean useAsy [InlineData(false)] [InlineData(true)] public async Task ExecuteScalar_TargetTypeIsChar_ColumnValueIsStringWithLengthNotOne_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) @@ -282,7 +282,7 @@ Boolean useAsyncApi // Oracle doesn't allow to return an empty string, because it treats empty strings as NULLs. (await Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT ''", @@ -292,18 +292,18 @@ Boolean useAsyncApi .Should().ThrowAsync() .WithMessage( "The first column of the first row in the result set returned by the SQL statement contains " + - $"the value '' ({typeof(String)}), which could not be converted to the type {typeof(Char)}. " + + $"the value '' ({typeof(string)}), which could not be converted to the type {typeof(char)}. " + "See inner exception for details.*" )) .WithInnerException() .WithMessage( - $"Could not convert the string '' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } (await Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT 'ab'", @@ -313,12 +313,12 @@ Boolean useAsyncApi .Should().ThrowAsync() .WithMessage( "The first column of the first row in the result set returned by the SQL statement contains the " + - $"value 'ab' ({typeof(String)}), which could not be converted to the type {typeof(Char)}. See " + + $"value 'ab' ({typeof(string)}), which could not be converted to the type {typeof(char)}. See " + "inner exception for details.*" )) .WithInnerException() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } @@ -327,11 +327,11 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task - ExecuteScalar_TargetTypeIsChar_ColumnValueIsStringWithLengthOne_ShouldGetFirstCharacter(Boolean useAsyncApi) + ExecuteScalar_TargetTypeIsChar_ColumnValueIsStringWithLengthOne_ShouldGetFirstCharacter(bool useAsyncApi) { - var character = Generate.Single(); + var character = Generate.Single(); - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, $"SELECT '{character}'", @@ -344,7 +344,7 @@ public async Task [InlineData(false)] [InlineData(true)] public async Task ExecuteScalar_TargetTypeIsEnum_ColumnValueIsInteger_ShouldConvertIntegerToEnum( - Boolean useAsyncApi + bool useAsyncApi ) { var enumValue = Generate.Single(); @@ -352,7 +352,7 @@ Boolean useAsyncApi (await CallApi( useAsyncApi, this.Connection, - $"SELECT {(Int32)enumValue}", + $"SELECT {(int)enumValue}", cancellationToken: TestContext.Current.CancellationToken )) .Should().Be(enumValue); @@ -361,7 +361,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public Task ExecuteScalar_TargetTypeIsEnum_ColumnValueIsInvalidInteger_ShouldThrow(Boolean useAsyncApi) => + public Task ExecuteScalar_TargetTypeIsEnum_ColumnValueIsInvalidInteger_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi( useAsyncApi, @@ -379,7 +379,7 @@ public Task ExecuteScalar_TargetTypeIsEnum_ColumnValueIsInvalidInteger_ShouldThr [Theory] [InlineData(false)] [InlineData(true)] - public Task ExecuteScalar_TargetTypeIsEnum_ColumnValueIsInvalidString_ShouldThrow(Boolean useAsyncApi) => + public Task ExecuteScalar_TargetTypeIsEnum_ColumnValueIsInvalidString_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi( useAsyncApi, @@ -391,14 +391,14 @@ public Task ExecuteScalar_TargetTypeIsEnum_ColumnValueIsInvalidString_ShouldThro .Should().ThrowAsync() .WithMessage( "The first column of the first row in the result set returned by the SQL statement contains the " + - $"value 'NonExistent' ({typeof(String)}), which could not be converted to the type " + + $"value 'NonExistent' ({typeof(string)}), which could not be converted to the type " + $"{typeof(TestEnum)}.*" ); [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteScalar_TargetTypeIsEnum_ColumnValueIsString_ShouldConvertStringToEnum(Boolean useAsyncApi) + public async Task ExecuteScalar_TargetTypeIsEnum_ColumnValueIsString_ShouldConvertStringToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); @@ -414,9 +414,9 @@ public async Task ExecuteScalar_TargetTypeIsEnum_ColumnValueIsString_ShouldConve [Theory] [InlineData(false)] [InlineData(true)] - public Task ExecuteScalar_TargetTypeIsNonNullable_ColumnValueIsNull_ShouldThrow(Boolean useAsyncApi) => + public Task ExecuteScalar_TargetTypeIsNonNullable_ColumnValueIsNull_ShouldThrow(bool useAsyncApi) => Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT NULL", @@ -426,14 +426,14 @@ public Task ExecuteScalar_TargetTypeIsNonNullable_ColumnValueIsNull_ShouldThrow( .Should().ThrowAsync() .WithMessage( "The first column of the first row in the result set returned by the SQL statement contains a NULL " + - $"value, which could not be converted to the type {typeof(Int32)}.*" + $"value, which could not be converted to the type {typeof(int)}.*" ); [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteScalar_TargetTypeIsNullable_ColumnValueIsNull_ShouldReturnNull(Boolean useAsyncApi) => - (await CallApi( + public async Task ExecuteScalar_TargetTypeIsNullable_ColumnValueIsNull_ShouldReturnNull(bool useAsyncApi) => + (await CallApi( useAsyncApi, this.Connection, "SELECT NULL", @@ -444,13 +444,13 @@ public async Task ExecuteScalar_TargetTypeIsNullable_ColumnValueIsNull_ShouldRet [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteScalar_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task ExecuteScalar_Transaction_ShouldUseTransaction(bool useAsyncApi) { await using (var transaction = await this.Connection.BeginTransactionAsync()) { var entity = this.CreateEntityInDb(transaction); - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("StringValue")} FROM {Q("Entity")}", @@ -462,7 +462,7 @@ public async Task ExecuteScalar_Transaction_ShouldUseTransaction(Boolean useAsyn await transaction.RollbackAsync(); } - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("StringValue")} FROM {Q("Entity")}", @@ -472,7 +472,7 @@ public async Task ExecuteScalar_Transaction_ShouldUseTransaction(Boolean useAsyn } private static Task CallApi( - Boolean useAsyncApi, + bool useAsyncApi, DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExistsTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExistsTests.cs index 8ee17ed..882ad42 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExistsTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExistsTests.cs @@ -29,7 +29,7 @@ public abstract class [Theory] [InlineData(false)] [InlineData(true)] - public async Task Exists_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(Boolean useAsyncApi) + public async Task Exists_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -45,7 +45,7 @@ await Invoking(() => CallApi(useAsyncApi, this.Connection, "SELECT 1", cancellat [Theory] [InlineData(false)] [InlineData(true)] - public async Task Exists_CommandType_ShouldUseCommandType(Boolean useAsyncApi) + public async Task Exists_CommandType_ShouldUseCommandType(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsStoredProceduresReturningResultSet, ""); @@ -64,7 +64,7 @@ public async Task Exists_CommandType_ShouldUseCommandType(Boolean useAsyncApi) [Theory] [InlineData(false)] [InlineData(true)] - public async Task Exists_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution(Boolean useAsyncApi) + public async Task Exists_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -95,7 +95,7 @@ SELECT 1 [InlineData(true)] public async Task Exists_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -118,7 +118,7 @@ SELECT 1 [Theory] [InlineData(false)] [InlineData(true)] - public async Task Exists_InterpolatedParameter_ShouldPassInterpolatedParameter(Boolean useAsyncApi) + public async Task Exists_InterpolatedParameter_ShouldPassInterpolatedParameter(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -134,7 +134,7 @@ public async Task Exists_InterpolatedParameter_ShouldPassInterpolatedParameter(B [Theory] [InlineData(false)] [InlineData(true)] - public async Task Exists_Parameter_ShouldPassParameter(Boolean useAsyncApi) + public async Task Exists_Parameter_ShouldPassParameter(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -155,7 +155,7 @@ public async Task Exists_Parameter_ShouldPassParameter(Boolean useAsyncApi) [Theory] [InlineData(false)] [InlineData(true)] - public async Task Exists_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(Boolean useAsyncApi) + public async Task Exists_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -182,7 +182,7 @@ public async Task Exists_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfte [InlineData(false)] [InlineData(true)] public async Task Exists_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -201,7 +201,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task Exists_ShouldReturnBooleanIndicatingWhetherQueryReturnedAtLeastOneRow(Boolean useAsyncApi) + public async Task Exists_ShouldReturnBooleanIndicatingWhetherQueryReturnedAtLeastOneRow(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -225,7 +225,7 @@ public async Task Exists_ShouldReturnBooleanIndicatingWhetherQueryReturnedAtLeas [Theory] [InlineData(false)] [InlineData(true)] - public async Task Exists_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task Exists_Transaction_ShouldUseTransaction(bool useAsyncApi) { await using (var transaction = await this.Connection.BeginTransactionAsync()) { @@ -252,8 +252,8 @@ public async Task Exists_Transaction_ShouldUseTransaction(Boolean useAsyncApi) .Should().BeFalse(); } - private static Task CallApi( - Boolean useAsyncApi, + private static Task CallApi( + bool useAsyncApi, DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, @@ -281,7 +281,7 @@ private static Task CallApi( } catch (Exception ex) { - return Task.FromException(ex); + return Task.FromException(ex); } } } diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ParameterTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ParameterTests.cs index 7d32fe8..a288227 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ParameterTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ParameterTests.cs @@ -36,11 +36,11 @@ public void Parameter_EnumValue_EnumSerializationModeIsIntegers_ShouldSerializeE var enumValue1 = Generate.Single(); this.Connection - .ExecuteScalar( + .ExecuteScalar( $"SELECT {Parameter(enumValue1)}", cancellationToken: TestContext.Current.CancellationToken ) - .Should().Be((Int32)enumValue1); + .Should().Be((int)enumValue1); } [Fact] @@ -55,7 +55,7 @@ public void Parameter_EnumValue_EnumSerializationModeIsStrings_ShouldSerializeEn var enumValue2 = Generate.Single(); this.Connection - .ExecuteScalar( + .ExecuteScalar( $"SELECT {Parameter(enumValue2)}", cancellationToken: TestContext.Current.CancellationToken ) @@ -65,12 +65,12 @@ public void Parameter_EnumValue_EnumSerializationModeIsStrings_ShouldSerializeEn [Fact] public void Parameter_MultipleParameters_ShouldPassValuesAsParameters() { - const Int64 int64 = 123L; + const long int64 = 123L; var guid = Guid.NewGuid(); var dateTime = new DateTime(2025, 12, 31, 23, 59, 59); this.Connection - .QuerySingle<(Int64, Guid, DateTime)>( + .QuerySingle<(long, Guid, DateTime)>( $"SELECT {Parameter(int64)}, {Parameter(guid)}, {Parameter(dateTime)}", cancellationToken: TestContext.Current.CancellationToken ) @@ -80,9 +80,9 @@ public void Parameter_MultipleParameters_ShouldPassValuesAsParameters() [Fact] public void Parameter_ShouldPassValueAsParameter() { - const Int64 int64 = 123L; + const long int64 = 123L; this.Connection - .ExecuteScalar( + .ExecuteScalar( $"SELECT {Parameter(int64)}", cancellationToken: TestContext.Current.CancellationToken ) diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOfTTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOfTTests.cs index de5ae7a..b005868 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOfTTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOfTTests.cs @@ -30,7 +30,7 @@ public abstract class [InlineData(false)] [InlineData(true)] public async Task QueryFirst_BuiltInType_CharTargetType_ColumnContainsStringWithLengthNotOne_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) @@ -38,7 +38,7 @@ Boolean useAsyncApi // Oracle doesn't allow to return an empty string, because it treats empty strings as NULLs. (await Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT ''", @@ -47,18 +47,18 @@ Boolean useAsyncApi ) .Should().ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value '' ({typeof(String)}), " + - $"which could not be converted to the type {typeof(Char)}. See inner exception for details.*" + $"The first column returned by the SQL statement contains the value '' ({typeof(string)}), " + + $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" )) .WithInnerException() .WithMessage( - $"Could not convert the string '' to the type {typeof(Char)}. The string must be exactly " + + $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly " + "one character long." ); } (await Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT 'ab'", @@ -67,12 +67,12 @@ Boolean useAsyncApi ) .Should().ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value 'ab' ({typeof(String)}), " + - $"which could not be converted to the type {typeof(Char)}. See inner exception for details.*" + $"The first column returned by the SQL statement contains the value 'ab' ({typeof(string)}), " + + $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" )) .WithInnerException() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be exactly " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + "one character long." ); } @@ -82,12 +82,12 @@ Boolean useAsyncApi [InlineData(true)] public async Task QueryFirst_BuiltInType_CharTargetType_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - Boolean useAsyncApi + bool useAsyncApi ) { - var character = Generate.Single(); + var character = Generate.Single(); - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, $"SELECT '{character}'", @@ -99,9 +99,9 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public Task QueryFirst_BuiltInType_ColumnValueCannotBeConvertedToTargetType_ShouldThrow(Boolean useAsyncApi) => + public Task QueryFirst_BuiltInType_ColumnValueCannotBeConvertedToTargetType_ShouldThrow(bool useAsyncApi) => Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT 'A'", @@ -110,14 +110,14 @@ public Task QueryFirst_BuiltInType_ColumnValueCannotBeConvertedToTargetType_Shou ) .Should().ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value 'A' ({typeof(String)}), which " + - $"could not be converted to the type {typeof(Int32)}. See inner exception for details.*" + $"The first column returned by the SQL statement contains the value 'A' ({typeof(string)}), which " + + $"could not be converted to the type {typeof(int)}. See inner exception for details.*" ); [Theory] [InlineData(false)] [InlineData(true)] - public Task QueryFirst_BuiltInType_EnumTargetType_ColumnContainsInvalidInteger_ShouldThrow(Boolean useAsyncApi) => + public Task QueryFirst_BuiltInType_EnumTargetType_ColumnContainsInvalidInteger_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi( useAsyncApi, @@ -135,7 +135,7 @@ public Task QueryFirst_BuiltInType_EnumTargetType_ColumnContainsInvalidInteger_S [Theory] [InlineData(false)] [InlineData(true)] - public Task QueryFirst_BuiltInType_EnumTargetType_ColumnContainsInvalidString_ShouldThrow(Boolean useAsyncApi) => + public Task QueryFirst_BuiltInType_EnumTargetType_ColumnContainsInvalidString_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi( useAsyncApi, @@ -147,21 +147,21 @@ public Task QueryFirst_BuiltInType_EnumTargetType_ColumnContainsInvalidString_Sh .Should().ThrowAsync() .WithMessage( "The first column returned by the SQL statement contains the value 'NonExistent' " + - $"({typeof(String)}), which could not be converted to the type {typeof(TestEnum)}. See inner " + + $"({typeof(string)}), which could not be converted to the type {typeof(TestEnum)}. See inner " + "exception for details.*" ); [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_BuiltInType_EnumTargetType_ShouldConvertIntegerToEnum(Boolean useAsyncApi) + public async Task QueryFirst_BuiltInType_EnumTargetType_ShouldConvertIntegerToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); (await CallApi( useAsyncApi, this.Connection, - $"SELECT {(Int32)enumValue}", + $"SELECT {(int)enumValue}", cancellationToken: TestContext.Current.CancellationToken )) .Should().Be(enumValue); @@ -170,7 +170,7 @@ public async Task QueryFirst_BuiltInType_EnumTargetType_ShouldConvertIntegerToEn [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_BuiltInType_EnumTargetType_ShouldConvertStringToEnum(Boolean useAsyncApi) + public async Task QueryFirst_BuiltInType_EnumTargetType_ShouldConvertStringToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); @@ -186,9 +186,9 @@ public async Task QueryFirst_BuiltInType_EnumTargetType_ShouldConvertStringToEnu [Theory] [InlineData(false)] [InlineData(true)] - public Task QueryFirst_BuiltInType_NonNullableTargetType_ColumnContainsNull_ShouldThrow(Boolean useAsyncApi) => + public Task QueryFirst_BuiltInType_NonNullableTargetType_ColumnContainsNull_ShouldThrow(bool useAsyncApi) => Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT NULL", @@ -198,16 +198,16 @@ public Task QueryFirst_BuiltInType_NonNullableTargetType_ColumnContainsNull_Shou .Should().ThrowAsync() .WithMessage( "The first column returned by the SQL statement contains a NULL value, which could not be converted " + - $"to the type {typeof(Int32)}. See inner exception for details.*" + $"to the type {typeof(int)}. See inner exception for details.*" ); [Theory] [InlineData(false)] [InlineData(true)] public async Task QueryFirst_BuiltInType_NullableTargetType_ColumnContainsNull_ShouldReturnNull( - Boolean useAsyncApi + bool useAsyncApi ) => - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, "SELECT NULL", @@ -218,7 +218,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_BuiltInType_ShouldSupportDateTimeOffsetValues(Boolean useAsyncApi) + public async Task QueryFirst_BuiltInType_ShouldSupportDateTimeOffsetValues(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); @@ -236,7 +236,7 @@ public async Task QueryFirst_BuiltInType_ShouldSupportDateTimeOffsetValues(Boole [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(Boolean useAsyncApi) + public async Task QueryFirst_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -259,7 +259,7 @@ await Invoking(() => [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_CommandType_ShouldUseCommandType(Boolean useAsyncApi) + public async Task QueryFirst_CommandType_ShouldUseCommandType(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsStoredProceduresReturningResultSet, ""); @@ -279,7 +279,7 @@ public async Task QueryFirst_CommandType_ShouldUseCommandType(Boolean useAsyncAp [InlineData(false)] [InlineData(true)] public async Task - QueryFirst_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution(Boolean useAsyncApi) + QueryFirst_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -306,7 +306,7 @@ public async Task [InlineData(true)] public async Task QueryFirst_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -326,7 +326,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task - QueryFirst_EntityType_CharEntityProperty_ColumnContainsStringWithLengthNotOne_ShouldThrow(Boolean useAsyncApi) + QueryFirst_EntityType_CharEntityProperty_ColumnContainsStringWithLengthNotOne_ShouldThrow(bool useAsyncApi) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) { @@ -343,12 +343,12 @@ await Invoking(() => .Should().ThrowAsync() .WithMessage( "The column 'CharValue' returned by the SQL statement contains a value that could not be " + - $"converted to the type {typeof(Char)} of the corresponding property of the type " + + $"converted to the type {typeof(char)} of the corresponding property of the type " + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string '' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } @@ -364,12 +364,12 @@ await Invoking(() => .Should().ThrowAsync() .WithMessage( "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(Char)} of the corresponding property of the type " + + $"to the type {typeof(char)} of the corresponding property of the type " + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } @@ -379,10 +379,10 @@ await Invoking(() => [InlineData(true)] public async Task QueryFirst_EntityType_CharEntityProperty_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - Boolean useAsyncApi + bool useAsyncApi ) { - var character = Generate.Single(); + var character = Generate.Single(); (await CallApi( useAsyncApi, @@ -397,7 +397,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task QueryFirst_EntityType_ColumnDataTypeNotCompatibleWithEntityPropertyType_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi( @@ -417,7 +417,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_EntityType_ColumnHasNoName_ShouldThrow(Boolean useAsyncApi) + public async Task QueryFirst_EntityType_ColumnHasNoName_ShouldThrow(bool useAsyncApi) { InterpolatedSqlStatement statement = this.TestDatabaseProvider switch { @@ -450,7 +450,7 @@ await Invoking(() => [InlineData(false)] [InlineData(true)] public async Task QueryFirst_EntityType_CompatiblePrivateConstructor_ShouldUsePrivateConstructor( - Boolean useAsyncApi + bool useAsyncApi ) { var entities = this.CreateEntitiesInDb(2); @@ -467,7 +467,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_EntityType_CompatiblePublicConstructor_ShouldUsePublicConstructor(Boolean useAsyncApi) + public async Task QueryFirst_EntityType_CompatiblePublicConstructor_ShouldUsePublicConstructor(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(2); @@ -484,7 +484,7 @@ public async Task QueryFirst_EntityType_CompatiblePublicConstructor_ShouldUsePub [InlineData(false)] [InlineData(true)] public async Task QueryFirst_EntityType_EntityTypeHasNoCorrespondingPropertyForColumn_ShouldIgnoreColumn( - Boolean useAsyncApi + bool useAsyncApi ) { var entity = (await Invoking(() => @@ -505,7 +505,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task QueryFirst_EntityType_EntityTypeWithPropertiesWithDifferentCasing_ShouldMaterializeEntities( - Boolean useAsyncApi + bool useAsyncApi ) { var entities = this.CreateEntitiesInDb(2); @@ -524,7 +524,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task QueryFirst_EntityType_EnumEntityProperty_ColumnContainsInvalidInteger_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => await Invoking(() => CallApi( useAsyncApi, @@ -549,7 +549,7 @@ await Invoking(() => CallApi( [InlineData(false)] [InlineData(true)] public async Task QueryFirst_EntityType_EnumEntityProperty_ColumnContainsInvalidString_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => await Invoking(() => CallApi( useAsyncApi, @@ -573,14 +573,14 @@ await Invoking(() => CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_EntityType_EnumEntityProperty_ShouldConvertIntegerToEnum(Boolean useAsyncApi) + public async Task QueryFirst_EntityType_EnumEntityProperty_ShouldConvertIntegerToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); (await CallApi( useAsyncApi, this.Connection, - $"SELECT 1 AS {Q("Id")}, {(Int32)enumValue} AS {Q("Enum")}", + $"SELECT 1 AS {Q("Id")}, {(int)enumValue} AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken )) .Enum @@ -590,7 +590,7 @@ public async Task QueryFirst_EntityType_EnumEntityProperty_ShouldConvertIntegerT [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_EntityType_EnumEntityProperty_ShouldConvertStringToEnum(Boolean useAsyncApi) + public async Task QueryFirst_EntityType_EnumEntityProperty_ShouldConvertStringToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); @@ -607,7 +607,7 @@ public async Task QueryFirst_EntityType_EnumEntityProperty_ShouldConvertStringTo [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_EntityType_Mapping_Attributes_ShouldUseAttributesMapping(Boolean useAsyncApi) + public async Task QueryFirst_EntityType_Mapping_Attributes_ShouldUseAttributesMapping(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -619,7 +619,7 @@ public async Task QueryFirst_EntityType_Mapping_Attributes_ShouldUseAttributesMa )) .Should().BeEquivalentTo( entity, - options => options.Using(context => context.Subject.Should().BeNull()) + options => options.Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -627,7 +627,7 @@ public async Task QueryFirst_EntityType_Mapping_Attributes_ShouldUseAttributesMa [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_EntityType_Mapping_FluentApi_ShouldUseFluentApiMapping(Boolean useAsyncApi) + public async Task QueryFirst_EntityType_Mapping_FluentApi_ShouldUseFluentApiMapping(bool useAsyncApi) { MappingTestEntityFluentApi.Configure(); @@ -641,7 +641,7 @@ public async Task QueryFirst_EntityType_Mapping_FluentApi_ShouldUseFluentApiMapp )) .Should().BeEquivalentTo( entity, - options => options.Using(context => context.Subject.Should().BeNull()) + options => options.Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -650,7 +650,7 @@ public async Task QueryFirst_EntityType_Mapping_FluentApi_ShouldUseFluentApiMapp [InlineData(false)] [InlineData(true)] public Task QueryFirst_EntityType_NoCompatibleConstructor_NoParameterlessConstructor_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi(useAsyncApi, this.Connection, $"SELECT 1 AS {Q("NonExistent")}") @@ -669,7 +669,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QueryFirst_EntityType_NoCompatibleConstructor_PrivateParameterlessConstructor_ShouldUsePrivateConstructorAndProperties( - Boolean useAsyncApi + bool useAsyncApi ) { var entities = this.CreateEntitiesInDb(2); @@ -688,7 +688,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QueryFirst_EntityType_NoCompatibleConstructor_PublicParameterlessConstructor_ShouldUsePublicConstructorAndProperties( - Boolean useAsyncApi + bool useAsyncApi ) { var entities = this.CreateEntitiesInDb(2); @@ -705,7 +705,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_EntityType_NoMapping_ShouldUseEntityTypeNameAndPropertyNames(Boolean useAsyncApi) + public async Task QueryFirst_EntityType_NoMapping_ShouldUseEntityTypeNameAndPropertyNames(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -721,7 +721,7 @@ public async Task QueryFirst_EntityType_NoMapping_ShouldUseEntityTypeNameAndProp [Theory] [InlineData(false)] [InlineData(true)] - public Task QueryFirst_EntityType_NonNullableEntityProperty_ColumnContainsNull_ShouldThrow(Boolean useAsyncApi) + public Task QueryFirst_EntityType_NonNullableEntityProperty_ColumnContainsNull_ShouldThrow(bool useAsyncApi) { this.Connection.ExecuteNonQuery( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)" @@ -746,7 +746,7 @@ public Task QueryFirst_EntityType_NonNullableEntityProperty_ColumnContainsNull_S [InlineData(false)] [InlineData(true)] public async Task QueryFirst_EntityType_NullableEntityProperty_ColumnContainsNull_ShouldReturnNull( - Boolean useAsyncApi + bool useAsyncApi ) { await this.Connection.ExecuteNonQueryAsync( @@ -765,7 +765,7 @@ await this.Connection.ExecuteNonQueryAsync( [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_EntityType_ShouldSupportDateTimeOffsetValues(Boolean useAsyncApi) + public async Task QueryFirst_EntityType_ShouldSupportDateTimeOffsetValues(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); @@ -783,7 +783,7 @@ public async Task QueryFirst_EntityType_ShouldSupportDateTimeOffsetValues(Boolea [Theory] [InlineData(false)] [InlineData(true)] - public Task QueryFirst_EntityType_UnsupportedFieldType_ShouldThrow(Boolean useAsyncApi) + public Task QueryFirst_EntityType_UnsupportedFieldType_ShouldThrow(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.HasUnsupportedDataType, ""); @@ -806,7 +806,7 @@ public Task QueryFirst_EntityType_UnsupportedFieldType_ShouldThrow(Boolean useAs [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_InterpolatedParameter_ShouldPassInterpolatedParameter(Boolean useAsyncApi) + public async Task QueryFirst_InterpolatedParameter_ShouldPassInterpolatedParameter(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(2); @@ -822,7 +822,7 @@ public async Task QueryFirst_InterpolatedParameter_ShouldPassInterpolatedParamet [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_Parameter_ShouldPassParameter(Boolean useAsyncApi) + public async Task QueryFirst_Parameter_ShouldPassParameter(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(2); @@ -843,7 +843,7 @@ public async Task QueryFirst_Parameter_ShouldPassParameter(Boolean useAsyncApi) [Theory] [InlineData(false)] [InlineData(true)] - public Task QueryFirst_QueryReturnedNoRows_ShouldThrow(Boolean useAsyncApi) => + public Task QueryFirst_QueryReturnedNoRows_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi( useAsyncApi, this.Connection, @@ -860,7 +860,7 @@ public Task QueryFirst_QueryReturnedNoRows_ShouldThrow(Boolean useAsyncApi) => [InlineData(false)] [InlineData(true)] public async Task - QueryFirst_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(Boolean useAsyncApi) + QueryFirst_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -871,7 +871,7 @@ public async Task var temporaryTableName = statement.TemporaryTables[0].Name; - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, statement, @@ -888,7 +888,7 @@ public async Task [InlineData(true)] public async Task QueryFirst_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -912,7 +912,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task QueryFirst_Transaction_ShouldUseTransaction(bool useAsyncApi) { await using (var transaction = await this.Connection.BeginTransactionAsync()) { @@ -945,7 +945,7 @@ await Invoking(() => CallApi( [InlineData(true)] public async Task QueryFirst_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthNotOne_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) @@ -953,7 +953,7 @@ Boolean useAsyncApi // Oracle doesn't allow to return an empty string, because it treats empty strings as NULLs. await Invoking(() => - CallApi>( + CallApi>( useAsyncApi, this.Connection, $"SELECT '' AS {Q("Value")}", @@ -963,18 +963,18 @@ await Invoking(() => .Should().ThrowAsync() .WithMessage( "The column 'Value' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(Char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + $"to the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string '' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } await Invoking(() => - CallApi>( + CallApi>( useAsyncApi, this.Connection, $"SELECT 'ab' AS {Q("Value")}", @@ -984,12 +984,12 @@ await Invoking(() => .Should().ThrowAsync() .WithMessage( "The column 'Value' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(Char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + $"to the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } @@ -999,12 +999,12 @@ await Invoking(() => [InlineData(true)] public async Task QueryFirst_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - Boolean useAsyncApi + bool useAsyncApi ) { - var character = Generate.Single(); + var character = Generate.Single(); - (await CallApi>( + (await CallApi>( useAsyncApi, this.Connection, $"SELECT '{character}'", @@ -1017,7 +1017,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task QueryFirst_ValueTupleType_ColumnDataTypeNotCompatibleWithValueTupleFieldType_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi>( @@ -1038,7 +1038,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task QueryFirst_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidInteger_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi>( @@ -1064,7 +1064,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task QueryFirst_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidString_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi>( @@ -1089,14 +1089,14 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_ValueTupleType_EnumValueTupleField_ShouldConvertIntegerToEnum(Boolean useAsyncApi) + public async Task QueryFirst_ValueTupleType_EnumValueTupleField_ShouldConvertIntegerToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); (await CallApi>( useAsyncApi, this.Connection, - $"SELECT {(Int32)enumValue}", + $"SELECT {(int)enumValue}", cancellationToken: TestContext.Current.CancellationToken )) .Should().Be(ValueTuple.Create(enumValue)); @@ -1105,7 +1105,7 @@ public async Task QueryFirst_ValueTupleType_EnumValueTupleField_ShouldConvertInt [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_ValueTupleType_EnumValueTupleField_ShouldConvertStringToEnum(Boolean useAsyncApi) + public async Task QueryFirst_ValueTupleType_EnumValueTupleField_ShouldConvertStringToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); @@ -1121,14 +1121,14 @@ public async Task QueryFirst_ValueTupleType_EnumValueTupleField_ShouldConvertStr [Theory] [InlineData(false)] [InlineData(true)] - public Task QueryFirst_ValueTupleType_NonNullableValueTupleField_ColumnContainsNull_ShouldThrow(Boolean useAsyncApi) + public Task QueryFirst_ValueTupleType_NonNullableValueTupleField_ColumnContainsNull_ShouldThrow(bool useAsyncApi) { this.Connection.ExecuteNonQuery( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)" ); return Invoking(() => - CallApi>( + CallApi>( useAsyncApi, this.Connection, $"SELECT {Q("BooleanValue")} FROM {Q("Entity")}", @@ -1138,7 +1138,7 @@ public Task QueryFirst_ValueTupleType_NonNullableValueTupleField_ColumnContainsN .Should().ThrowAsync() .WithMessage( "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + - $"corresponding field of the value tuple type {typeof(ValueTuple)} is non-nullable.*" + $"corresponding field of the value tuple type {typeof(ValueTuple)} is non-nullable.*" ); } @@ -1146,14 +1146,14 @@ public Task QueryFirst_ValueTupleType_NonNullableValueTupleField_ColumnContainsN [InlineData(false)] [InlineData(true)] public async Task QueryFirst_ValueTupleType_NullableValueTupleField_ColumnContainsNull_ShouldReturnNull( - Boolean useAsyncApi + bool useAsyncApi ) { await this.Connection.ExecuteNonQueryAsync( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("NullableBooleanValue")}) VALUES(1, NULL)" ); - (await CallApi>( + (await CallApi>( useAsyncApi, this.Connection, $"SELECT {Q("NullableBooleanValue")} FROM {Q("Entity")}", @@ -1166,10 +1166,10 @@ await this.Connection.ExecuteNonQueryAsync( [InlineData(false)] [InlineData(true)] public Task QueryFirst_ValueTupleType_NumberOfColumnsDoesNotMatchNumberOfValueTupleFields_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => - CallApi<(Int32, Int32)>( + CallApi<(int, int)>( useAsyncApi, this.Connection, "SELECT 1", @@ -1178,7 +1178,7 @@ Boolean useAsyncApi ) .Should().ThrowAsync() .WithMessage( - $"The SQL statement returned 1 column, but the value tuple type {typeof((Int32, Int32))} has 2 " + + $"The SQL statement returned 1 column, but the value tuple type {typeof((int, int))} has 2 " + "fields. Make sure that the SQL statement returns the same number of columns as the number of " + "fields in the value tuple type.*" ); @@ -1186,11 +1186,11 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_ValueTupleType_ShouldMaterializeBinaryData(Boolean useAsyncApi) + public async Task QueryFirst_ValueTupleType_ShouldMaterializeBinaryData(bool useAsyncApi) { - var bytes = Generate.Single(); + var bytes = Generate.Single(); - (await CallApi>( + (await CallApi>( useAsyncApi, this.Connection, $"SELECT {Parameter(bytes)} AS BinaryData", @@ -1202,13 +1202,13 @@ public async Task QueryFirst_ValueTupleType_ShouldMaterializeBinaryData(Boolean [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_ValueTupleType_ShouldSupportDateTimeOffsetValues(Boolean useAsyncApi) + public async Task QueryFirst_ValueTupleType_ShouldSupportDateTimeOffsetValues(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); var entities = this.CreateEntitiesInDb(2); - (await CallApi<(Int64 Id, DateTimeOffset DateTimeOffsetValue)>( + (await CallApi<(long Id, DateTimeOffset DateTimeOffsetValue)>( useAsyncApi, this.Connection, $"SELECT {Q("Id")}, {Q("DateTimeOffsetValue")} FROM {Q("EntityWithDateTimeOffset")}", @@ -1220,14 +1220,14 @@ public async Task QueryFirst_ValueTupleType_ShouldSupportDateTimeOffsetValues(Bo [Theory] [InlineData(false)] [InlineData(true)] - public Task QueryFirst_ValueTupleType_UnsupportedFieldType_ShouldThrow(Boolean useAsyncApi) + public Task QueryFirst_ValueTupleType_UnsupportedFieldType_ShouldThrow(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.HasUnsupportedDataType, ""); var literal = this.TestDatabaseProvider.GetUnsupportedDataTypeLiteral(); return Invoking(() => - CallApi>( + CallApi>( useAsyncApi, this.Connection, $"SELECT {literal} AS {Q("Value")}", @@ -1241,7 +1241,7 @@ public Task QueryFirst_ValueTupleType_UnsupportedFieldType_ShouldThrow(Boolean u } private static Task CallApi( - Boolean useAsyncApi, + bool useAsyncApi, DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOrDefaultOfTTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOrDefaultOfTTests.cs index 073e68f..8933e91 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOrDefaultOfTTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOrDefaultOfTTests.cs @@ -32,7 +32,7 @@ public abstract class [InlineData(true)] public async Task QueryFirstOrDefault_BuiltInType_CharTargetType_ColumnContainsStringWithLengthNotOne_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) @@ -40,7 +40,7 @@ Boolean useAsyncApi // Oracle doesn't allow to return an empty string, because it treats empty strings as NULLs. (await Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT ''", @@ -49,18 +49,18 @@ Boolean useAsyncApi ) .Should().ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value '' ({typeof(String)}), " + - $"which could not be converted to the type {typeof(Char)}. See inner exception for details.*" + $"The first column returned by the SQL statement contains the value '' ({typeof(string)}), " + + $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" )) .WithInnerException() .WithMessage( - $"Could not convert the string '' to the type {typeof(Char)}. The string must be exactly " + + $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly " + "one character long." ); } (await Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT 'ab'", @@ -69,12 +69,12 @@ Boolean useAsyncApi ) .Should().ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value 'ab' ({typeof(String)}), " + - $"which could not be converted to the type {typeof(Char)}. See inner exception for details.*" + $"The first column returned by the SQL statement contains the value 'ab' ({typeof(string)}), " + + $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" )) .WithInnerException() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be exactly " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + "one character long." ); } @@ -84,12 +84,12 @@ Boolean useAsyncApi [InlineData(true)] public async Task QueryFirstOrDefault_BuiltInType_CharTargetType_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - Boolean useAsyncApi + bool useAsyncApi ) { - var character = Generate.Single(); + var character = Generate.Single(); - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, $"SELECT '{character}'", @@ -102,10 +102,10 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task QueryFirstOrDefault_BuiltInType_ColumnValueCannotBeConvertedToTargetType_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT 'A'", @@ -114,15 +114,15 @@ Boolean useAsyncApi ) .Should().ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value 'A' ({typeof(String)}), which " + - $"could not be converted to the type {typeof(Int32)}. See inner exception for details.*" + $"The first column returned by the SQL statement contains the value 'A' ({typeof(string)}), which " + + $"could not be converted to the type {typeof(int)}. See inner exception for details.*" ); [Theory] [InlineData(false)] [InlineData(true)] public Task QueryFirstOrDefault_BuiltInType_EnumTargetType_ColumnContainsInvalidInteger_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi( @@ -142,7 +142,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task QueryFirstOrDefault_BuiltInType_EnumTargetType_ColumnContainsInvalidString_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi( @@ -155,21 +155,21 @@ Boolean useAsyncApi .Should().ThrowAsync() .WithMessage( "The first column returned by the SQL statement contains the value 'NonExistent' " + - $"({typeof(String)}), which could not be converted to the type {typeof(TestEnum)}. See inner " + + $"({typeof(string)}), which could not be converted to the type {typeof(TestEnum)}. See inner " + "exception for details.*" ); [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_BuiltInType_EnumTargetType_ShouldConvertIntegerToEnum(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_BuiltInType_EnumTargetType_ShouldConvertIntegerToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); (await CallApi( useAsyncApi, this.Connection, - $"SELECT {(Int32)enumValue}", + $"SELECT {(int)enumValue}", cancellationToken: TestContext.Current.CancellationToken )) .Should().Be(enumValue); @@ -178,7 +178,7 @@ public async Task QueryFirstOrDefault_BuiltInType_EnumTargetType_ShouldConvertIn [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_BuiltInType_EnumTargetType_ShouldConvertStringToEnum(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_BuiltInType_EnumTargetType_ShouldConvertStringToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); @@ -195,10 +195,10 @@ public async Task QueryFirstOrDefault_BuiltInType_EnumTargetType_ShouldConvertSt [InlineData(false)] [InlineData(true)] public Task QueryFirstOrDefault_BuiltInType_NonNullableTargetType_ColumnContainsNull_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT NULL", @@ -208,16 +208,16 @@ Boolean useAsyncApi .Should().ThrowAsync() .WithMessage( "The first column returned by the SQL statement contains a NULL value, which could not be converted " + - $"to the type {typeof(Int32)}. See inner exception for details.*" + $"to the type {typeof(int)}. See inner exception for details.*" ); [Theory] [InlineData(false)] [InlineData(true)] public async Task QueryFirstOrDefault_BuiltInType_NullableTargetType_ColumnContainsNull_ShouldReturnNull( - Boolean useAsyncApi + bool useAsyncApi ) => - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, "SELECT NULL", @@ -228,7 +228,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_BuiltInType_ShouldSupportDateTimeOffsetValues(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_BuiltInType_ShouldSupportDateTimeOffsetValues(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); @@ -247,7 +247,7 @@ public async Task QueryFirstOrDefault_BuiltInType_ShouldSupportDateTimeOffsetVal [InlineData(false)] [InlineData(true)] public async Task QueryFirstOrDefault_CancellationToken_ShouldCancelOperationIfCancellationIsRequested( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -271,7 +271,7 @@ await Invoking(() => [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_CommandType_ShouldUseCommandType(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_CommandType_ShouldUseCommandType(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsStoredProceduresReturningResultSet, ""); @@ -291,7 +291,7 @@ public async Task QueryFirstOrDefault_CommandType_ShouldUseCommandType(Boolean u [InlineData(false)] [InlineData(true)] public async Task - QueryFirstOrDefault_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution(Boolean useAsyncApi) + QueryFirstOrDefault_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -318,7 +318,7 @@ public async Task [InlineData(true)] public async Task QueryFirstOrDefault_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -339,7 +339,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QueryFirstOrDefault_EntityType_CharEntityProperty_ColumnContainsStringWithLengthNotOne_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) @@ -357,12 +357,12 @@ await Invoking(() => .Should().ThrowAsync() .WithMessage( "The column 'CharValue' returned by the SQL statement contains a value that could not be " + - $"converted to the type {typeof(Char)} of the corresponding property of the type " + + $"converted to the type {typeof(char)} of the corresponding property of the type " + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string '' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } @@ -378,12 +378,12 @@ await Invoking(() => .Should().ThrowAsync() .WithMessage( "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(Char)} of the corresponding property of the type " + + $"to the type {typeof(char)} of the corresponding property of the type " + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } @@ -393,10 +393,10 @@ await Invoking(() => [InlineData(true)] public async Task QueryFirstOrDefault_EntityType_CharEntityProperty_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - Boolean useAsyncApi + bool useAsyncApi ) { - var character = Generate.Single(); + var character = Generate.Single(); (await CallApi( useAsyncApi, @@ -411,7 +411,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task QueryFirstOrDefault_EntityType_ColumnDataTypeNotCompatibleWithEntityPropertyType_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi( @@ -431,7 +431,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_EntityType_ColumnHasNoName_ShouldThrow(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_EntityType_ColumnHasNoName_ShouldThrow(bool useAsyncApi) { InterpolatedSqlStatement statement = this.TestDatabaseProvider switch { @@ -464,7 +464,7 @@ await Invoking(() => [InlineData(false)] [InlineData(true)] public async Task QueryFirstOrDefault_EntityType_CompatiblePrivateConstructor_ShouldUsePrivateConstructor( - Boolean useAsyncApi + bool useAsyncApi ) { var entities = this.CreateEntitiesInDb(2); @@ -482,7 +482,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task QueryFirstOrDefault_EntityType_CompatiblePublicConstructor_ShouldUsePublicConstructor( - Boolean useAsyncApi + bool useAsyncApi ) { var entities = this.CreateEntitiesInDb(2); @@ -501,7 +501,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QueryFirstOrDefault_EntityType_EntityTypeHasNoCorrespondingPropertyForColumn_ShouldIgnoreColumn( - Boolean useAsyncApi + bool useAsyncApi ) { var entity = (await Invoking(() => @@ -523,7 +523,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QueryFirstOrDefault_EntityType_EntityTypeWithPropertiesWithDifferentCasing_ShouldMaterializeEntities( - Boolean useAsyncApi + bool useAsyncApi ) { var entities = this.CreateEntitiesInDb(2); @@ -543,7 +543,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QueryFirstOrDefault_EntityType_EnumEntityProperty_ColumnContainsInvalidInteger_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => await Invoking(() => CallApi( useAsyncApi, @@ -569,7 +569,7 @@ await Invoking(() => CallApi( [InlineData(true)] public async Task QueryFirstOrDefault_EntityType_EnumEntityProperty_ColumnContainsInvalidString_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => await Invoking(() => CallApi( useAsyncApi, @@ -593,14 +593,14 @@ await Invoking(() => CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_EntityType_EnumEntityProperty_ShouldConvertIntegerToEnum(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_EntityType_EnumEntityProperty_ShouldConvertIntegerToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); (await CallApi( useAsyncApi, this.Connection, - $"SELECT 1 AS {Q("Id")}, {(Int32)enumValue} AS {Q("Enum")}", + $"SELECT 1 AS {Q("Id")}, {(int)enumValue} AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken ))! .Enum @@ -610,7 +610,7 @@ public async Task QueryFirstOrDefault_EntityType_EnumEntityProperty_ShouldConver [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_EntityType_EnumEntityProperty_ShouldConvertStringToEnum(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_EntityType_EnumEntityProperty_ShouldConvertStringToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); @@ -627,7 +627,7 @@ public async Task QueryFirstOrDefault_EntityType_EnumEntityProperty_ShouldConver [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_EntityType_Mapping_Attributes_ShouldUseAttributesMapping(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_EntityType_Mapping_Attributes_ShouldUseAttributesMapping(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -639,7 +639,7 @@ public async Task QueryFirstOrDefault_EntityType_Mapping_Attributes_ShouldUseAtt )) .Should().BeEquivalentTo( entity, - options => options.Using(context => context.Subject.Should().BeNull()) + options => options.Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -647,7 +647,7 @@ public async Task QueryFirstOrDefault_EntityType_Mapping_Attributes_ShouldUseAtt [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_EntityType_Mapping_FluentApi_ShouldUseFluentApiMapping(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_EntityType_Mapping_FluentApi_ShouldUseFluentApiMapping(bool useAsyncApi) { MappingTestEntityFluentApi.Configure(); @@ -661,7 +661,7 @@ public async Task QueryFirstOrDefault_EntityType_Mapping_FluentApi_ShouldUseFlue )) .Should().BeEquivalentTo( entity, - options => options.Using(context => context.Subject.Should().BeNull()) + options => options.Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -670,7 +670,7 @@ public async Task QueryFirstOrDefault_EntityType_Mapping_FluentApi_ShouldUseFlue [InlineData(false)] [InlineData(true)] public Task QueryFirstOrDefault_EntityType_NoCompatibleConstructor_NoParameterlessConstructor_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi(useAsyncApi, this.Connection, $"SELECT 1 AS {Q("NonExistent")}") @@ -689,7 +689,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QueryFirstOrDefault_EntityType_NoCompatibleConstructor_PrivateParameterlessConstructor_ShouldUsePrivateConstructorAndProperties( - Boolean useAsyncApi + bool useAsyncApi ) { var entities = this.CreateEntitiesInDb(2); @@ -708,7 +708,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QueryFirstOrDefault_EntityType_NoCompatibleConstructor_PublicParameterlessConstructor_ShouldUsePublicConstructorAndProperties( - Boolean useAsyncApi + bool useAsyncApi ) { var entities = this.CreateEntitiesInDb(2); @@ -726,7 +726,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task QueryFirstOrDefault_EntityType_NoMapping_ShouldUseEntityTypeNameAndPropertyNames( - Boolean useAsyncApi + bool useAsyncApi ) { var entity = this.CreateEntityInDb(); @@ -744,7 +744,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task QueryFirstOrDefault_EntityType_NonNullableEntityProperty_ColumnContainsNull_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) { this.Connection.ExecuteNonQuery( @@ -770,7 +770,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task QueryFirstOrDefault_EntityType_NullableEntityProperty_ColumnContainsNull_ShouldReturnNull( - Boolean useAsyncApi + bool useAsyncApi ) { await this.Connection.ExecuteNonQueryAsync( @@ -789,7 +789,7 @@ await this.Connection.ExecuteNonQueryAsync( [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_EntityType_ShouldSupportDateTimeOffsetValues(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_EntityType_ShouldSupportDateTimeOffsetValues(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); @@ -807,7 +807,7 @@ public async Task QueryFirstOrDefault_EntityType_ShouldSupportDateTimeOffsetValu [Theory] [InlineData(false)] [InlineData(true)] - public Task QueryFirstOrDefault_EntityType_UnsupportedFieldType_ShouldThrow(Boolean useAsyncApi) + public Task QueryFirstOrDefault_EntityType_UnsupportedFieldType_ShouldThrow(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.HasUnsupportedDataType, ""); @@ -830,7 +830,7 @@ public Task QueryFirstOrDefault_EntityType_UnsupportedFieldType_ShouldThrow(Bool [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_InterpolatedParameter_ShouldPassInterpolatedParameter(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_InterpolatedParameter_ShouldPassInterpolatedParameter(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(2); @@ -846,7 +846,7 @@ public async Task QueryFirstOrDefault_InterpolatedParameter_ShouldPassInterpolat [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_Parameter_ShouldPassParameter(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_Parameter_ShouldPassParameter(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(2); @@ -867,9 +867,9 @@ public async Task QueryFirstOrDefault_Parameter_ShouldPassParameter(Boolean useA [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_QueryReturnedNoRows_ShouldReturnDefault(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_QueryReturnedNoRows_ShouldReturnDefault(bool useAsyncApi) { - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("Id")} FROM {Q("Entity")} WHERE {Q("Id")} = -1", @@ -885,7 +885,7 @@ public async Task QueryFirstOrDefault_QueryReturnedNoRows_ShouldReturnDefault(Bo )) .Should().BeNull(); - (await CallApi<(Int64, String)>( + (await CallApi<(long, string)>( useAsyncApi, this.Connection, $"SELECT {Q("Id")}, {Q("StringValue")} FROM {Q("Entity")} WHERE {Q("Id")} = -1", @@ -898,7 +898,7 @@ public async Task QueryFirstOrDefault_QueryReturnedNoRows_ShouldReturnDefault(Bo [InlineData(false)] [InlineData(true)] public async Task - QueryFirstOrDefault_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(Boolean useAsyncApi) + QueryFirstOrDefault_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -909,7 +909,7 @@ public async Task var temporaryTableName = statement.TemporaryTables[0].Name; - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, statement, @@ -926,7 +926,7 @@ public async Task [InlineData(true)] public async Task QueryFirstOrDefault_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -950,7 +950,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_Transaction_ShouldUseTransaction(bool useAsyncApi) { await using (var transaction = await this.Connection.BeginTransactionAsync()) { @@ -982,7 +982,7 @@ public async Task QueryFirstOrDefault_Transaction_ShouldUseTransaction(Boolean u [InlineData(true)] public async Task QueryFirstOrDefault_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthNotOne_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) @@ -990,7 +990,7 @@ Boolean useAsyncApi // Oracle doesn't allow to return an empty string, because it treats empty strings as NULLs. await Invoking(() => - CallApi>( + CallApi>( useAsyncApi, this.Connection, $"SELECT '' AS {Q("Value")}", @@ -1000,18 +1000,18 @@ await Invoking(() => .Should().ThrowAsync() .WithMessage( "The column 'Value' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(Char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + $"to the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string '' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } await Invoking(() => - CallApi>( + CallApi>( useAsyncApi, this.Connection, $"SELECT 'ab' AS {Q("Value")}", @@ -1021,12 +1021,12 @@ await Invoking(() => .Should().ThrowAsync() .WithMessage( "The column 'Value' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(Char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + $"to the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } @@ -1036,12 +1036,12 @@ await Invoking(() => [InlineData(true)] public async Task QueryFirstOrDefault_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - Boolean useAsyncApi + bool useAsyncApi ) { - var character = Generate.Single(); + var character = Generate.Single(); - (await CallApi>( + (await CallApi>( useAsyncApi, this.Connection, $"SELECT '{character}'", @@ -1055,7 +1055,7 @@ Boolean useAsyncApi [InlineData(true)] public Task QueryFirstOrDefault_ValueTupleType_ColumnDataTypeNotCompatibleWithValueTupleFieldType_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi>( @@ -1077,7 +1077,7 @@ Boolean useAsyncApi [InlineData(true)] public Task QueryFirstOrDefault_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidInteger_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi>( @@ -1103,7 +1103,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task QueryFirstOrDefault_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidString_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi>( @@ -1129,7 +1129,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task QueryFirstOrDefault_ValueTupleType_EnumValueTupleField_ShouldConvertIntegerToEnum( - Boolean useAsyncApi + bool useAsyncApi ) { var enumValue = Generate.Single(); @@ -1137,7 +1137,7 @@ Boolean useAsyncApi (await CallApi>( useAsyncApi, this.Connection, - $"SELECT {(Int32)enumValue}", + $"SELECT {(int)enumValue}", cancellationToken: TestContext.Current.CancellationToken )) .Should().Be(ValueTuple.Create(enumValue)); @@ -1147,7 +1147,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task QueryFirstOrDefault_ValueTupleType_EnumValueTupleField_ShouldConvertStringToEnum( - Boolean useAsyncApi + bool useAsyncApi ) { var enumValue = Generate.Single(); @@ -1165,7 +1165,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task QueryFirstOrDefault_ValueTupleType_NonNullableValueTupleField_ColumnContainsNull_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) { this.Connection.ExecuteNonQuery( @@ -1173,7 +1173,7 @@ Boolean useAsyncApi ); return Invoking(() => - CallApi>( + CallApi>( useAsyncApi, this.Connection, $"SELECT {Q("BooleanValue")} FROM {Q("Entity")}", @@ -1183,7 +1183,7 @@ Boolean useAsyncApi .Should().ThrowAsync() .WithMessage( "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + - $"corresponding field of the value tuple type {typeof(ValueTuple)} is non-nullable.*" + $"corresponding field of the value tuple type {typeof(ValueTuple)} is non-nullable.*" ); } @@ -1192,14 +1192,14 @@ Boolean useAsyncApi [InlineData(true)] public async Task QueryFirstOrDefault_ValueTupleType_NullableValueTupleField_ColumnContainsNull_ShouldReturnNull( - Boolean useAsyncApi + bool useAsyncApi ) { await this.Connection.ExecuteNonQueryAsync( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("NullableBooleanValue")}) VALUES(1, NULL)" ); - (await CallApi>( + (await CallApi>( useAsyncApi, this.Connection, $"SELECT {Q("NullableBooleanValue")} FROM {Q("Entity")}", @@ -1213,10 +1213,10 @@ await this.Connection.ExecuteNonQueryAsync( [InlineData(true)] public Task QueryFirstOrDefault_ValueTupleType_NumberOfColumnsDoesNotMatchNumberOfValueTupleFields_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => - CallApi<(Int32, Int32)>( + CallApi<(int, int)>( useAsyncApi, this.Connection, "SELECT 1", @@ -1225,7 +1225,7 @@ Boolean useAsyncApi ) .Should().ThrowAsync() .WithMessage( - $"The SQL statement returned 1 column, but the value tuple type {typeof((Int32, Int32))} has 2 " + + $"The SQL statement returned 1 column, but the value tuple type {typeof((int, int))} has 2 " + "fields. Make sure that the SQL statement returns the same number of columns as the number of " + "fields in the value tuple type.*" ); @@ -1233,11 +1233,11 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_ValueTupleType_ShouldMaterializeBinaryData(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_ValueTupleType_ShouldMaterializeBinaryData(bool useAsyncApi) { - var bytes = Generate.Single(); + var bytes = Generate.Single(); - (await CallApi>( + (await CallApi>( useAsyncApi, this.Connection, $"SELECT {Parameter(bytes)} AS BinaryData", @@ -1249,13 +1249,13 @@ public async Task QueryFirstOrDefault_ValueTupleType_ShouldMaterializeBinaryData [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_ValueTupleType_ShouldSupportDateTimeOffsetValues(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_ValueTupleType_ShouldSupportDateTimeOffsetValues(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); var entities = this.CreateEntitiesInDb(2); - (await CallApi<(Int64 Id, DateTimeOffset DateTimeOffsetValue)>( + (await CallApi<(long Id, DateTimeOffset DateTimeOffsetValue)>( useAsyncApi, this.Connection, $"SELECT {Q("Id")}, {Q("DateTimeOffsetValue")} FROM {Q("EntityWithDateTimeOffset")}", @@ -1267,14 +1267,14 @@ public async Task QueryFirstOrDefault_ValueTupleType_ShouldSupportDateTimeOffset [Theory] [InlineData(false)] [InlineData(true)] - public Task QueryFirstOrDefault_ValueTupleType_UnsupportedFieldType_ShouldThrow(Boolean useAsyncApi) + public Task QueryFirstOrDefault_ValueTupleType_UnsupportedFieldType_ShouldThrow(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.HasUnsupportedDataType, ""); var literal = this.TestDatabaseProvider.GetUnsupportedDataTypeLiteral(); return Invoking(() => - CallApi>( + CallApi>( useAsyncApi, this.Connection, $"SELECT {literal} AS {Q("Value")}", @@ -1288,7 +1288,7 @@ public Task QueryFirstOrDefault_ValueTupleType_UnsupportedFieldType_ShouldThrow( } private static Task CallApi( - Boolean useAsyncApi, + bool useAsyncApi, DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOrDefaultTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOrDefaultTests.cs index a723cf6..732b516 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOrDefaultTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOrDefaultTests.cs @@ -32,7 +32,7 @@ public abstract class [InlineData(false)] [InlineData(true)] public async Task QueryFirstOrDefault_CancellationToken_ShouldCancelOperationIfCancellationIsRequested( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -56,7 +56,7 @@ await Invoking(() => [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_CommandType_ShouldUseCommandType(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_CommandType_ShouldUseCommandType(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsStoredProceduresReturningResultSet, ""); @@ -77,7 +77,7 @@ public async Task QueryFirstOrDefault_CommandType_ShouldUseCommandType(Boolean u [InlineData(false)] [InlineData(true)] public async Task QueryFirstOrDefault_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -106,7 +106,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QueryFirstOrDefault_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -126,7 +126,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_InterpolatedParameter_ShouldPassInterpolatedParameter(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_InterpolatedParameter_ShouldPassInterpolatedParameter(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(2); @@ -143,7 +143,7 @@ public async Task QueryFirstOrDefault_InterpolatedParameter_ShouldPassInterpolat [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_Parameter_ShouldPassParameter(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_Parameter_ShouldPassParameter(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(2); @@ -166,8 +166,8 @@ public async Task QueryFirstOrDefault_Parameter_ShouldPassParameter(Boolean useA [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_QueryReturnedNoRows_ShouldReturnNull(Boolean useAsyncApi) => - ((Object?)await CallApi( + public async Task QueryFirstOrDefault_QueryReturnedNoRows_ShouldReturnNull(bool useAsyncApi) => + ((object?)await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")} WHERE {Q("Id")} = -1", @@ -179,7 +179,7 @@ public async Task QueryFirstOrDefault_QueryReturnedNoRows_ShouldReturnNull(Boole [InlineData(false)] [InlineData(true)] public async Task QueryFirstOrDefault_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -212,7 +212,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QueryFirstOrDefault_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -226,14 +226,14 @@ Boolean useAsyncApi cancellationToken: TestContext.Current.CancellationToken ); - ValueConverter.ConvertValueToType(dataRow!["Id"]) + ValueConverter.ConvertValueToType(dataRow!["Id"]) .Should().Be(entityIds[0]); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_ShouldReturnDataRowForFirstRow(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_ShouldReturnDataRowForFirstRow(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(2); @@ -250,7 +250,7 @@ public async Task QueryFirstOrDefault_ShouldReturnDataRowForFirstRow(Boolean use [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task QueryFirstOrDefault_Transaction_ShouldUseTransaction(bool useAsyncApi) { await using (var transaction = await this.Connection.BeginTransactionAsync()) { @@ -269,7 +269,7 @@ public async Task QueryFirstOrDefault_Transaction_ShouldUseTransaction(Boolean u await transaction.RollbackAsync(); } - ((Object?)await CallApi( + ((object?)await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", @@ -279,7 +279,7 @@ public async Task QueryFirstOrDefault_Transaction_ShouldUseTransaction(Boolean u } private static Task CallApi( - Boolean useAsyncApi, + bool useAsyncApi, DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstTests.cs index 7430727..b249da4 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstTests.cs @@ -31,7 +31,7 @@ public abstract class [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(Boolean useAsyncApi) + public async Task QueryFirst_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -54,7 +54,7 @@ await Invoking(() => [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_CommandType_ShouldUseCommandType(Boolean useAsyncApi) + public async Task QueryFirst_CommandType_ShouldUseCommandType(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsStoredProceduresReturningResultSet, ""); @@ -75,7 +75,7 @@ public async Task QueryFirst_CommandType_ShouldUseCommandType(Boolean useAsyncAp [InlineData(false)] [InlineData(true)] public async Task QueryFirst_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -104,7 +104,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QueryFirst_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -124,7 +124,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_InterpolatedParameter_ShouldPassInterpolatedParameter(Boolean useAsyncApi) + public async Task QueryFirst_InterpolatedParameter_ShouldPassInterpolatedParameter(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(2); @@ -141,7 +141,7 @@ public async Task QueryFirst_InterpolatedParameter_ShouldPassInterpolatedParamet [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_Parameter_ShouldPassParameter(Boolean useAsyncApi) + public async Task QueryFirst_Parameter_ShouldPassParameter(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(2); @@ -164,7 +164,7 @@ public async Task QueryFirst_Parameter_ShouldPassParameter(Boolean useAsyncApi) [Theory] [InlineData(false)] [InlineData(true)] - public Task QueryFirst_QueryReturnedNoRows_ShouldThrow(Boolean useAsyncApi) => + public Task QueryFirst_QueryReturnedNoRows_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi( useAsyncApi, this.Connection, @@ -180,7 +180,7 @@ public Task QueryFirst_QueryReturnedNoRows_ShouldThrow(Boolean useAsyncApi) => [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(Boolean useAsyncApi) + public async Task QueryFirst_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -212,7 +212,7 @@ public async Task QueryFirst_ScalarValuesTemporaryTable_ShouldDropTemporaryTable [InlineData(true)] public async Task QueryFirst_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -226,14 +226,14 @@ Boolean useAsyncApi cancellationToken: TestContext.Current.CancellationToken ); - ValueConverter.ConvertValueToType(dataRow["Id"]) + ValueConverter.ConvertValueToType(dataRow["Id"]) .Should().Be(entityIds[0]); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_ShouldReturnDataRowForFirstRow(Boolean useAsyncApi) + public async Task QueryFirst_ShouldReturnDataRowForFirstRow(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(2); @@ -250,7 +250,7 @@ public async Task QueryFirst_ShouldReturnDataRowForFirstRow(Boolean useAsyncApi) [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task QueryFirst_Transaction_ShouldUseTransaction(bool useAsyncApi) { await using (var transaction = await this.Connection.BeginTransactionAsync()) { @@ -283,7 +283,7 @@ await Invoking(() => CallApi( } private static Task CallApi( - Boolean useAsyncApi, + bool useAsyncApi, DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryOfTTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryOfTTests.cs index 7ad6a72..e5ea63d 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryOfTTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryOfTTests.cs @@ -30,7 +30,7 @@ public abstract class [InlineData(false)] [InlineData(true)] public async Task Query_BuiltInType_CharTargetType_ColumnContainsStringWithLengthNotOne_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) @@ -38,7 +38,7 @@ Boolean useAsyncApi // Oracle doesn't allow to return an empty string, because it treats empty strings as NULLs. (await Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT ''", @@ -47,18 +47,18 @@ Boolean useAsyncApi ) .Should().ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value '' ({typeof(String)}), " + - $"which could not be converted to the type {typeof(Char)}. See inner exception for details.*" + $"The first column returned by the SQL statement contains the value '' ({typeof(string)}), " + + $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" )) .WithInnerException() .WithMessage( - $"Could not convert the string '' to the type {typeof(Char)}. The string must be exactly " + + $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly " + "one character long." ); } (await Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT 'ab'", @@ -67,12 +67,12 @@ Boolean useAsyncApi ) .Should().ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value 'ab' ({typeof(String)}), " + - $"which could not be converted to the type {typeof(Char)}. See inner exception for details.*" + $"The first column returned by the SQL statement contains the value 'ab' ({typeof(string)}), " + + $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" )) .WithInnerException() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be exactly " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + "one character long." ); } @@ -81,12 +81,12 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task Query_BuiltInType_CharTargetType_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - Boolean useAsyncApi + bool useAsyncApi ) { - var character = Generate.Single(); + var character = Generate.Single(); - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, $"SELECT '{character}'", @@ -98,9 +98,9 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public Task Query_BuiltInType_ColumnValueCannotBeConvertedToTargetType_ShouldThrow(Boolean useAsyncApi) => + public Task Query_BuiltInType_ColumnValueCannotBeConvertedToTargetType_ShouldThrow(bool useAsyncApi) => Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT 'A'", @@ -109,14 +109,14 @@ public Task Query_BuiltInType_ColumnValueCannotBeConvertedToTargetType_ShouldThr ) .Should().ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value 'A' ({typeof(String)}), which " + - $"could not be converted to the type {typeof(Int32)}. See inner exception for details.*" + $"The first column returned by the SQL statement contains the value 'A' ({typeof(string)}), which " + + $"could not be converted to the type {typeof(int)}. See inner exception for details.*" ); [Theory] [InlineData(false)] [InlineData(true)] - public Task Query_BuiltInType_EnumTargetType_ColumnContainsInvalidInteger_ShouldThrow(Boolean useAsyncApi) => + public Task Query_BuiltInType_EnumTargetType_ColumnContainsInvalidInteger_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi( useAsyncApi, @@ -134,7 +134,7 @@ public Task Query_BuiltInType_EnumTargetType_ColumnContainsInvalidInteger_Should [Theory] [InlineData(false)] [InlineData(true)] - public Task Query_BuiltInType_EnumTargetType_ColumnContainsInvalidString_ShouldThrow(Boolean useAsyncApi) => + public Task Query_BuiltInType_EnumTargetType_ColumnContainsInvalidString_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi( useAsyncApi, @@ -146,21 +146,21 @@ public Task Query_BuiltInType_EnumTargetType_ColumnContainsInvalidString_ShouldT .Should().ThrowAsync() .WithMessage( "The first column returned by the SQL statement contains the value 'NonExistent' " + - $"({typeof(String)}), which could not be converted to the type {typeof(TestEnum)}. See inner " + + $"({typeof(string)}), which could not be converted to the type {typeof(TestEnum)}. See inner " + "exception for details.*" ); [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_BuiltInType_EnumTargetType_ShouldConvertIntegerToEnum(Boolean useAsyncApi) + public async Task Query_BuiltInType_EnumTargetType_ShouldConvertIntegerToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); (await CallApi( useAsyncApi, this.Connection, - $"SELECT {(Int32)enumValue}", + $"SELECT {(int)enumValue}", cancellationToken: TestContext.Current.CancellationToken ).ToListAsync(TestContext.Current.CancellationToken)) .Should().BeEquivalentTo([enumValue]); @@ -169,7 +169,7 @@ public async Task Query_BuiltInType_EnumTargetType_ShouldConvertIntegerToEnum(Bo [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_BuiltInType_EnumTargetType_ShouldConvertStringToEnum(Boolean useAsyncApi) + public async Task Query_BuiltInType_EnumTargetType_ShouldConvertStringToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); @@ -185,9 +185,9 @@ public async Task Query_BuiltInType_EnumTargetType_ShouldConvertStringToEnum(Boo [Theory] [InlineData(false)] [InlineData(true)] - public Task Query_BuiltInType_NonNullableTargetType_ColumnContainsNull_ShouldThrow(Boolean useAsyncApi) => + public Task Query_BuiltInType_NonNullableTargetType_ColumnContainsNull_ShouldThrow(bool useAsyncApi) => Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT NULL", @@ -197,26 +197,26 @@ public Task Query_BuiltInType_NonNullableTargetType_ColumnContainsNull_ShouldThr .Should().ThrowAsync() .WithMessage( "The first column returned by the SQL statement contains a NULL value, which could not be converted " + - $"to the type {typeof(Int32)}. See inner exception for details.*" + $"to the type {typeof(int)}. See inner exception for details.*" ); [Theory] [InlineData(false)] [InlineData(true)] public async Task - Query_BuiltInType_NullableTargetType_ColumnContainsNull_ShouldReturnNull(Boolean useAsyncApi) => - (await CallApi( + Query_BuiltInType_NullableTargetType_ColumnContainsNull_ShouldReturnNull(bool useAsyncApi) => + (await CallApi( useAsyncApi, this.Connection, "SELECT NULL", cancellationToken: TestContext.Current.CancellationToken ).ToListAsync(TestContext.Current.CancellationToken).AsTask()) - .Should().BeEquivalentTo(new Int32?[] { null }); + .Should().BeEquivalentTo(new int?[] { null }); [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_BuiltInType_ShouldSupportDateTimeOffsetValues(Boolean useAsyncApi) + public async Task Query_BuiltInType_ShouldSupportDateTimeOffsetValues(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); @@ -234,7 +234,7 @@ public async Task Query_BuiltInType_ShouldSupportDateTimeOffsetValues(Boolean us [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(Boolean useAsyncApi) + public async Task Query_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -257,7 +257,7 @@ await Invoking(() => [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_CommandType_ShouldUseCommandType(Boolean useAsyncApi) + public async Task Query_CommandType_ShouldUseCommandType(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsStoredProceduresReturningResultSet, ""); @@ -277,7 +277,7 @@ public async Task Query_CommandType_ShouldUseCommandType(Boolean useAsyncApi) [InlineData(false)] [InlineData(true)] public async Task - Query_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterEnumerationIsFinished(Boolean useAsyncApi) + Query_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterEnumerationIsFinished(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -319,7 +319,7 @@ public async Task [InlineData(false)] [InlineData(true)] public async Task - Query_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable(Boolean useAsyncApi) + Query_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -338,7 +338,7 @@ public async Task [InlineData(false)] [InlineData(true)] public async Task - Query_EntityType_CharEntityProperty_ColumnContainsStringWithLengthNotOne_ShouldThrow(Boolean useAsyncApi) + Query_EntityType_CharEntityProperty_ColumnContainsStringWithLengthNotOne_ShouldThrow(bool useAsyncApi) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) { @@ -355,12 +355,12 @@ await Invoking(() => .Should().ThrowAsync() .WithMessage( "The column 'CharValue' returned by the SQL statement contains a value that could not be " + - $"converted to the type {typeof(Char)} of the corresponding property of the type " + + $"converted to the type {typeof(char)} of the corresponding property of the type " + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string '' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } @@ -376,12 +376,12 @@ await Invoking(() => .Should().ThrowAsync() .WithMessage( "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(Char)} of the corresponding property of the type " + + $"to the type {typeof(char)} of the corresponding property of the type " + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } @@ -391,10 +391,10 @@ await Invoking(() => [InlineData(true)] public async Task Query_EntityType_CharEntityProperty_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - Boolean useAsyncApi + bool useAsyncApi ) { - var character = Generate.Single(); + var character = Generate.Single(); (await CallApi( useAsyncApi, @@ -408,7 +408,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public Task Query_EntityType_ColumnDataTypeNotCompatibleWithEntityPropertyType_ShouldThrow(Boolean useAsyncApi) => + public Task Query_EntityType_ColumnDataTypeNotCompatibleWithEntityPropertyType_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi( useAsyncApi, @@ -427,7 +427,7 @@ public Task Query_EntityType_ColumnDataTypeNotCompatibleWithEntityPropertyType_S [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_EntityType_ColumnHasNoName_ShouldThrow(Boolean useAsyncApi) + public async Task Query_EntityType_ColumnHasNoName_ShouldThrow(bool useAsyncApi) { InterpolatedSqlStatement statement = this.TestDatabaseProvider switch { @@ -459,7 +459,7 @@ await Invoking(() => [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_EntityType_CompatiblePrivateConstructor_ShouldUsePrivateConstructor(Boolean useAsyncApi) + public async Task Query_EntityType_CompatiblePrivateConstructor_ShouldUsePrivateConstructor(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(); @@ -475,7 +475,7 @@ public async Task Query_EntityType_CompatiblePrivateConstructor_ShouldUsePrivate [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_EntityType_CompatiblePublicConstructor_ShouldUsePublicConstructor(Boolean useAsyncApi) + public async Task Query_EntityType_CompatiblePublicConstructor_ShouldUsePublicConstructor(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(); @@ -492,7 +492,7 @@ public async Task Query_EntityType_CompatiblePublicConstructor_ShouldUsePublicCo [InlineData(false)] [InlineData(true)] public async Task Query_EntityType_EntityTypeHasNoCorrespondingPropertyForColumn_ShouldIgnoreColumn( - Boolean useAsyncApi + bool useAsyncApi ) { var entities = (await Invoking(() => @@ -513,7 +513,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task Query_EntityType_EntityTypeWithPropertiesWithDifferentCasing_ShouldMaterializeEntities( - Boolean useAsyncApi + bool useAsyncApi ) { var entities = this.CreateEntitiesInDb(); @@ -532,7 +532,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task Query_EntityType_EnumEntityProperty_ColumnContainsInvalidInteger_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => await Invoking(() => CallApi( useAsyncApi, @@ -557,7 +557,7 @@ await Invoking(() => CallApi( [InlineData(false)] [InlineData(true)] public async Task Query_EntityType_EnumEntityProperty_ColumnContainsInvalidString_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => await Invoking(() => CallApi( useAsyncApi, @@ -581,14 +581,14 @@ await Invoking(() => CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_EntityType_EnumEntityProperty_ShouldConvertIntegerToEnum(Boolean useAsyncApi) + public async Task Query_EntityType_EnumEntityProperty_ShouldConvertIntegerToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); (await CallApi( useAsyncApi, this.Connection, - $"SELECT 1 AS {Q("Id")}, {(Int32)enumValue} AS {Q("Enum")}", + $"SELECT 1 AS {Q("Id")}, {(int)enumValue} AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken ).FirstAsync()) .Enum @@ -598,7 +598,7 @@ public async Task Query_EntityType_EnumEntityProperty_ShouldConvertIntegerToEnum [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_EntityType_EnumEntityProperty_ShouldConvertStringToEnum(Boolean useAsyncApi) + public async Task Query_EntityType_EnumEntityProperty_ShouldConvertStringToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); @@ -615,7 +615,7 @@ public async Task Query_EntityType_EnumEntityProperty_ShouldConvertStringToEnum( [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_EntityType_Mapping_Attributes_ShouldUseAttributesMapping(Boolean useAsyncApi) + public async Task Query_EntityType_Mapping_Attributes_ShouldUseAttributesMapping(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(); @@ -627,7 +627,7 @@ public async Task Query_EntityType_Mapping_Attributes_ShouldUseAttributesMapping ).ToListAsync(TestContext.Current.CancellationToken)) .Should().BeEquivalentTo( entities, - options => options.Using(context => context.Subject.Should().BeNull()) + options => options.Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -635,7 +635,7 @@ public async Task Query_EntityType_Mapping_Attributes_ShouldUseAttributesMapping [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_EntityType_Mapping_FluentApi_ShouldUseFluentApiMapping(Boolean useAsyncApi) + public async Task Query_EntityType_Mapping_FluentApi_ShouldUseFluentApiMapping(bool useAsyncApi) { MappingTestEntityFluentApi.Configure(); @@ -649,7 +649,7 @@ public async Task Query_EntityType_Mapping_FluentApi_ShouldUseFluentApiMapping(B ).ToListAsync(TestContext.Current.CancellationToken)) .Should().BeEquivalentTo( entities, - options => options.Using(context => context.Subject.Should().BeNull()) + options => options.Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -657,7 +657,7 @@ public async Task Query_EntityType_Mapping_FluentApi_ShouldUseFluentApiMapping(B [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_EntityType_Mapping_NoMapping_ShouldUseEntityTypeNameAndPropertyNames(Boolean useAsyncApi) + public async Task Query_EntityType_Mapping_NoMapping_ShouldUseEntityTypeNameAndPropertyNames(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(); @@ -673,7 +673,7 @@ public async Task Query_EntityType_Mapping_NoMapping_ShouldUseEntityTypeNameAndP [Theory] [InlineData(false)] [InlineData(true)] - public Task Query_EntityType_NoCompatibleConstructor_NoParameterlessConstructor_ShouldThrow(Boolean useAsyncApi) => + public Task Query_EntityType_NoCompatibleConstructor_NoParameterlessConstructor_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi(useAsyncApi, this.Connection, $"SELECT 1 AS {Q("NonExistent")}") .ToListAsync(TestContext.Current.CancellationToken).AsTask() @@ -692,7 +692,7 @@ public Task Query_EntityType_NoCompatibleConstructor_NoParameterlessConstructor_ [InlineData(true)] public async Task Query_EntityType_NoCompatibleConstructor_PrivateParameterlessConstructor_ShouldUsePrivateConstructorAndProperties( - Boolean useAsyncApi + bool useAsyncApi ) { var entities = this.CreateEntitiesInDb(); @@ -711,7 +711,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task Query_EntityType_NoCompatibleConstructor_PublicParameterlessConstructor_ShouldUsePublicConstructorAndProperties( - Boolean useAsyncApi + bool useAsyncApi ) { var entities = this.CreateEntitiesInDb(); @@ -728,7 +728,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public Task Query_EntityType_NonNullableEntityProperty_ColumnContainsNull_ShouldThrow(Boolean useAsyncApi) + public Task Query_EntityType_NonNullableEntityProperty_ColumnContainsNull_ShouldThrow(bool useAsyncApi) { this.Connection.ExecuteNonQuery( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)" @@ -752,7 +752,7 @@ public Task Query_EntityType_NonNullableEntityProperty_ColumnContainsNull_Should [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_EntityType_NullableEntityProperty_ColumnContainsNull_ShouldReturnNull(Boolean useAsyncApi) + public async Task Query_EntityType_NullableEntityProperty_ColumnContainsNull_ShouldReturnNull(bool useAsyncApi) { await this.Connection.ExecuteNonQueryAsync( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("NullableBooleanValue")}) VALUES(1, NULL)" @@ -770,7 +770,7 @@ await this.Connection.ExecuteNonQueryAsync( [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_EntityType_ShouldSupportDateTimeOffsetValues(Boolean useAsyncApi) + public async Task Query_EntityType_ShouldSupportDateTimeOffsetValues(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); @@ -788,7 +788,7 @@ public async Task Query_EntityType_ShouldSupportDateTimeOffsetValues(Boolean use [Theory] [InlineData(false)] [InlineData(true)] - public Task Query_EntityType_UnsupportedFieldType_ShouldThrow(Boolean useAsyncApi) + public Task Query_EntityType_UnsupportedFieldType_ShouldThrow(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.HasUnsupportedDataType, ""); @@ -811,7 +811,7 @@ public Task Query_EntityType_UnsupportedFieldType_ShouldThrow(Boolean useAsyncAp [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_InterpolatedParameter_ShouldPassInterpolatedParameter(Boolean useAsyncApi) + public async Task Query_InterpolatedParameter_ShouldPassInterpolatedParameter(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -827,7 +827,7 @@ public async Task Query_InterpolatedParameter_ShouldPassInterpolatedParameter(Bo [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_Parameter_ShouldPassParameter(Boolean useAsyncApi) + public async Task Query_Parameter_ShouldPassParameter(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -849,7 +849,7 @@ public async Task Query_Parameter_ShouldPassParameter(Boolean useAsyncApi) [InlineData(false)] [InlineData(true)] public async Task - Query_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterEnumerationIsFinished(Boolean useAsyncApi) + Query_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterEnumerationIsFinished(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -892,7 +892,7 @@ public async Task [InlineData(false)] [InlineData(true)] public async Task - Query_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable(Boolean useAsyncApi) + Query_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -915,7 +915,7 @@ public async Task [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task Query_Transaction_ShouldUseTransaction(bool useAsyncApi) { await using (var transaction = await this.Connection.BeginTransactionAsync()) { @@ -946,7 +946,7 @@ public async Task Query_Transaction_ShouldUseTransaction(Boolean useAsyncApi) [InlineData(false)] [InlineData(true)] public async Task Query_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthNotOne_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) @@ -954,7 +954,7 @@ Boolean useAsyncApi // Oracle doesn't allow to return an empty string, because it treats empty strings as NULLs. await Invoking(() => - CallApi>( + CallApi>( useAsyncApi, this.Connection, $"SELECT '' AS {Q("Value")}", @@ -964,18 +964,18 @@ await Invoking(() => .Should().ThrowAsync() .WithMessage( "The column 'Value' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(Char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + $"to the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string '' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } await Invoking(() => - CallApi>( + CallApi>( useAsyncApi, this.Connection, $"SELECT 'ab' AS {Q("Value")}", @@ -985,12 +985,12 @@ await Invoking(() => .Should().ThrowAsync() .WithMessage( "The column 'Value' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(Char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + $"to the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } @@ -1000,12 +1000,12 @@ await Invoking(() => [InlineData(true)] public async Task Query_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - Boolean useAsyncApi + bool useAsyncApi ) { - var character = Generate.Single(); + var character = Generate.Single(); - (await CallApi>( + (await CallApi>( useAsyncApi, this.Connection, $"SELECT '{character}'", @@ -1018,7 +1018,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task Query_ValueTupleType_ColumnDataTypeNotCompatibleWithValueTupleFieldType_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi>( @@ -1039,7 +1039,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task Query_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidInteger_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi>( @@ -1064,7 +1064,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public Task Query_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidString_ShouldThrow(Boolean useAsyncApi) => + public Task Query_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidString_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi>( useAsyncApi, @@ -1088,14 +1088,14 @@ public Task Query_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidString [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_ValueTupleType_EnumValueTupleField_ShouldConvertIntegerToEnum(Boolean useAsyncApi) + public async Task Query_ValueTupleType_EnumValueTupleField_ShouldConvertIntegerToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); (await CallApi>( useAsyncApi, this.Connection, - $"SELECT {(Int32)enumValue}", + $"SELECT {(int)enumValue}", cancellationToken: TestContext.Current.CancellationToken ).ToListAsync(TestContext.Current.CancellationToken)) .Should().BeEquivalentTo([ValueTuple.Create(enumValue)]); @@ -1104,7 +1104,7 @@ public async Task Query_ValueTupleType_EnumValueTupleField_ShouldConvertIntegerT [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_ValueTupleType_EnumValueTupleField_ShouldConvertStringToEnum(Boolean useAsyncApi) + public async Task Query_ValueTupleType_EnumValueTupleField_ShouldConvertStringToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); @@ -1120,14 +1120,14 @@ public async Task Query_ValueTupleType_EnumValueTupleField_ShouldConvertStringTo [Theory] [InlineData(false)] [InlineData(true)] - public Task Query_ValueTupleType_NonNullableValueTupleField_ColumnContainsNull_ShouldThrow(Boolean useAsyncApi) + public Task Query_ValueTupleType_NonNullableValueTupleField_ColumnContainsNull_ShouldThrow(bool useAsyncApi) { this.Connection.ExecuteNonQuery( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)" ); return Invoking(() => - CallApi>( + CallApi>( useAsyncApi, this.Connection, $"SELECT {Q("BooleanValue")} FROM {Q("Entity")}", @@ -1137,7 +1137,7 @@ public Task Query_ValueTupleType_NonNullableValueTupleField_ColumnContainsNull_S .Should().ThrowAsync() .WithMessage( "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + - $"corresponding field of the value tuple type {typeof(ValueTuple)} is non-nullable.*" + $"corresponding field of the value tuple type {typeof(ValueTuple)} is non-nullable.*" ); } @@ -1145,30 +1145,30 @@ public Task Query_ValueTupleType_NonNullableValueTupleField_ColumnContainsNull_S [InlineData(false)] [InlineData(true)] public async Task Query_ValueTupleType_NullableValueTupleField_ColumnContainsNull_ShouldReturnNull( - Boolean useAsyncApi + bool useAsyncApi ) { await this.Connection.ExecuteNonQueryAsync( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("NullableBooleanValue")}) VALUES(1, NULL)" ); - (await CallApi>( + (await CallApi>( useAsyncApi, this.Connection, $"SELECT {Q("NullableBooleanValue")} FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo([new ValueTuple(null)]); + .Should().BeEquivalentTo([new ValueTuple(null)]); } [Theory] [InlineData(false)] [InlineData(true)] public Task Query_ValueTupleType_NumberOfColumnsDoesNotMatchNumberOfValueTupleFields_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => - CallApi<(Int32, Int32)>( + CallApi<(int, int)>( useAsyncApi, this.Connection, "SELECT 1", @@ -1177,7 +1177,7 @@ Boolean useAsyncApi ) .Should().ThrowAsync() .WithMessage( - $"The SQL statement returned 1 column, but the value tuple type {typeof((Int32, Int32))} has 2 " + + $"The SQL statement returned 1 column, but the value tuple type {typeof((int, int))} has 2 " + "fields. Make sure that the SQL statement returns the same number of columns as the number of " + "fields in the value tuple type.*" ); @@ -1185,11 +1185,11 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_ValueTupleType_ShouldMaterializeBinaryData(Boolean useAsyncApi) + public async Task Query_ValueTupleType_ShouldMaterializeBinaryData(bool useAsyncApi) { - var bytes = Generate.Single(); + var bytes = Generate.Single(); - (await CallApi>( + (await CallApi>( useAsyncApi, this.Connection, $"SELECT {Parameter(bytes)} AS BinaryData", @@ -1201,13 +1201,13 @@ public async Task Query_ValueTupleType_ShouldMaterializeBinaryData(Boolean useAs [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_ValueTupleType_ShouldSupportDateTimeOffsetValues(Boolean useAsyncApi) + public async Task Query_ValueTupleType_ShouldSupportDateTimeOffsetValues(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); var entities = this.CreateEntitiesInDb(); - (await CallApi<(Int64 Id, DateTimeOffset DateTimeOffsetValue)>( + (await CallApi<(long Id, DateTimeOffset DateTimeOffsetValue)>( useAsyncApi, this.Connection, $"SELECT {Q("Id")}, {Q("DateTimeOffsetValue")} FROM {Q("EntityWithDateTimeOffset")}", @@ -1219,14 +1219,14 @@ public async Task Query_ValueTupleType_ShouldSupportDateTimeOffsetValues(Boolean [Theory] [InlineData(false)] [InlineData(true)] - public Task Query_ValueTupleType_UnsupportedFieldType_ShouldThrow(Boolean useAsyncApi) + public Task Query_ValueTupleType_UnsupportedFieldType_ShouldThrow(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.HasUnsupportedDataType, ""); var literal = this.TestDatabaseProvider.GetUnsupportedDataTypeLiteral(); return Invoking(() => - CallApi>( + CallApi>( useAsyncApi, this.Connection, $"SELECT {literal} AS {Q("Value")}", @@ -1240,7 +1240,7 @@ public Task Query_ValueTupleType_UnsupportedFieldType_ShouldThrow(Boolean useAsy } private static IAsyncEnumerable CallApi( - Boolean useAsyncApi, + bool useAsyncApi, DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOfTTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOfTTests.cs index 9ed0dd6..b6907bf 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOfTTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOfTTests.cs @@ -30,7 +30,7 @@ public abstract class [InlineData(false)] [InlineData(true)] public async Task QuerySingle_BuiltInType_CharTargetType_ColumnContainsStringWithLengthNotOne_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) @@ -38,7 +38,7 @@ Boolean useAsyncApi // Oracle doesn't allow to return an empty string, because it treats empty strings as NULLs. (await Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT ''", @@ -47,18 +47,18 @@ Boolean useAsyncApi ) .Should().ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value '' ({typeof(String)}), " + - $"which could not be converted to the type {typeof(Char)}. See inner exception for details.*" + $"The first column returned by the SQL statement contains the value '' ({typeof(string)}), " + + $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" )) .WithInnerException() .WithMessage( - $"Could not convert the string '' to the type {typeof(Char)}. The string must be exactly " + + $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly " + "one character long." ); } (await Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT 'ab'", @@ -67,12 +67,12 @@ Boolean useAsyncApi ) .Should().ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value 'ab' ({typeof(String)}), " + - $"which could not be converted to the type {typeof(Char)}. See inner exception for details.*" + $"The first column returned by the SQL statement contains the value 'ab' ({typeof(string)}), " + + $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" )) .WithInnerException() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be exactly " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + "one character long." ); } @@ -82,12 +82,12 @@ Boolean useAsyncApi [InlineData(true)] public async Task QuerySingle_BuiltInType_CharTargetType_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - Boolean useAsyncApi + bool useAsyncApi ) { - var character = Generate.Single(); + var character = Generate.Single(); - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, $"SELECT '{character}'", @@ -99,9 +99,9 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public Task QuerySingle_BuiltInType_ColumnValueCannotBeConvertedToTargetType_ShouldThrow(Boolean useAsyncApi) => + public Task QuerySingle_BuiltInType_ColumnValueCannotBeConvertedToTargetType_ShouldThrow(bool useAsyncApi) => Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT 'A'", @@ -110,14 +110,14 @@ public Task QuerySingle_BuiltInType_ColumnValueCannotBeConvertedToTargetType_Sho ) .Should().ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value 'A' ({typeof(String)}), which " + - $"could not be converted to the type {typeof(Int32)}. See inner exception for details.*" + $"The first column returned by the SQL statement contains the value 'A' ({typeof(string)}), which " + + $"could not be converted to the type {typeof(int)}. See inner exception for details.*" ); [Theory] [InlineData(false)] [InlineData(true)] - public Task QuerySingle_BuiltInType_EnumTargetType_ColumnContainsInvalidInteger_ShouldThrow(Boolean useAsyncApi) => + public Task QuerySingle_BuiltInType_EnumTargetType_ColumnContainsInvalidInteger_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi( useAsyncApi, @@ -135,7 +135,7 @@ public Task QuerySingle_BuiltInType_EnumTargetType_ColumnContainsInvalidInteger_ [Theory] [InlineData(false)] [InlineData(true)] - public Task QuerySingle_BuiltInType_EnumTargetType_ColumnContainsInvalidString_ShouldThrow(Boolean useAsyncApi) => + public Task QuerySingle_BuiltInType_EnumTargetType_ColumnContainsInvalidString_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi( useAsyncApi, @@ -147,21 +147,21 @@ public Task QuerySingle_BuiltInType_EnumTargetType_ColumnContainsInvalidString_S .Should().ThrowAsync() .WithMessage( "The first column returned by the SQL statement contains the value 'NonExistent' " + - $"({typeof(String)}), which could not be converted to the type {typeof(TestEnum)}. See inner " + + $"({typeof(string)}), which could not be converted to the type {typeof(TestEnum)}. See inner " + "exception for details.*" ); [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_BuiltInType_EnumTargetType_ShouldConvertIntegerToEnum(Boolean useAsyncApi) + public async Task QuerySingle_BuiltInType_EnumTargetType_ShouldConvertIntegerToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); (await CallApi( useAsyncApi, this.Connection, - $"SELECT {(Int32)enumValue}", + $"SELECT {(int)enumValue}", cancellationToken: TestContext.Current.CancellationToken )) .Should().Be(enumValue); @@ -170,7 +170,7 @@ public async Task QuerySingle_BuiltInType_EnumTargetType_ShouldConvertIntegerToE [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_BuiltInType_EnumTargetType_ShouldConvertStringToEnum(Boolean useAsyncApi) + public async Task QuerySingle_BuiltInType_EnumTargetType_ShouldConvertStringToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); @@ -186,9 +186,9 @@ public async Task QuerySingle_BuiltInType_EnumTargetType_ShouldConvertStringToEn [Theory] [InlineData(false)] [InlineData(true)] - public Task QuerySingle_BuiltInType_NonNullableTargetType_ColumnContainsNull_ShouldThrow(Boolean useAsyncApi) => + public Task QuerySingle_BuiltInType_NonNullableTargetType_ColumnContainsNull_ShouldThrow(bool useAsyncApi) => Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT NULL", @@ -198,16 +198,16 @@ public Task QuerySingle_BuiltInType_NonNullableTargetType_ColumnContainsNull_Sho .Should().ThrowAsync() .WithMessage( "The first column returned by the SQL statement contains a NULL value, which could not be converted " + - $"to the type {typeof(Int32)}. See inner exception for details.*" + $"to the type {typeof(int)}. See inner exception for details.*" ); [Theory] [InlineData(false)] [InlineData(true)] public async Task QuerySingle_BuiltInType_NullableTargetType_ColumnContainsNull_ShouldReturnNull( - Boolean useAsyncApi + bool useAsyncApi ) => - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, "SELECT NULL", @@ -218,7 +218,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_BuiltInType_ShouldSupportDateTimeOffsetValues(Boolean useAsyncApi) + public async Task QuerySingle_BuiltInType_ShouldSupportDateTimeOffsetValues(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); @@ -236,7 +236,7 @@ public async Task QuerySingle_BuiltInType_ShouldSupportDateTimeOffsetValues(Bool [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(Boolean useAsyncApi) + public async Task QuerySingle_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -259,7 +259,7 @@ await Invoking(() => [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_CommandType_ShouldUseCommandType(Boolean useAsyncApi) + public async Task QuerySingle_CommandType_ShouldUseCommandType(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsStoredProceduresReturningResultSet, ""); @@ -279,7 +279,7 @@ public async Task QuerySingle_CommandType_ShouldUseCommandType(Boolean useAsyncA [InlineData(false)] [InlineData(true)] public async Task - QuerySingle_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution(Boolean useAsyncApi) + QuerySingle_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -306,7 +306,7 @@ public async Task [InlineData(true)] public async Task QuerySingle_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -326,7 +326,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task - QuerySingle_EntityType_CharEntityProperty_ColumnContainsStringWithLengthNotOne_ShouldThrow(Boolean useAsyncApi) + QuerySingle_EntityType_CharEntityProperty_ColumnContainsStringWithLengthNotOne_ShouldThrow(bool useAsyncApi) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) { @@ -343,12 +343,12 @@ await Invoking(() => .Should().ThrowAsync() .WithMessage( "The column 'CharValue' returned by the SQL statement contains a value that could not be " + - $"converted to the type {typeof(Char)} of the corresponding property of the type " + + $"converted to the type {typeof(char)} of the corresponding property of the type " + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string '' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } @@ -364,12 +364,12 @@ await Invoking(() => .Should().ThrowAsync() .WithMessage( "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(Char)} of the corresponding property of the type " + + $"to the type {typeof(char)} of the corresponding property of the type " + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } @@ -379,10 +379,10 @@ await Invoking(() => [InlineData(true)] public async Task QuerySingle_EntityType_CharEntityProperty_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - Boolean useAsyncApi + bool useAsyncApi ) { - var character = Generate.Single(); + var character = Generate.Single(); (await CallApi( useAsyncApi, @@ -397,7 +397,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task QuerySingle_EntityType_ColumnDataTypeNotCompatibleWithEntityPropertyType_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi( @@ -417,7 +417,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_EntityType_ColumnHasNoName_ShouldThrow(Boolean useAsyncApi) + public async Task QuerySingle_EntityType_ColumnHasNoName_ShouldThrow(bool useAsyncApi) { InterpolatedSqlStatement statement = this.TestDatabaseProvider switch { @@ -450,7 +450,7 @@ await Invoking(() => [InlineData(false)] [InlineData(true)] public async Task QuerySingle_EntityType_CompatiblePrivateConstructor_ShouldUsePrivateConstructor( - Boolean useAsyncApi + bool useAsyncApi ) { var entity = this.CreateEntityInDb(); @@ -467,7 +467,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_EntityType_CompatiblePublicConstructor_ShouldUsePublicConstructor(Boolean useAsyncApi) + public async Task QuerySingle_EntityType_CompatiblePublicConstructor_ShouldUsePublicConstructor(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -484,7 +484,7 @@ public async Task QuerySingle_EntityType_CompatiblePublicConstructor_ShouldUsePu [InlineData(false)] [InlineData(true)] public async Task QuerySingle_EntityType_EntityTypeHasNoCorrespondingPropertyForColumn_ShouldIgnoreColumn( - Boolean useAsyncApi + bool useAsyncApi ) { var entity = (await Invoking(() => @@ -506,7 +506,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QuerySingle_EntityType_EntityTypeWithPropertiesWithDifferentCasing_ShouldMaterializeEntities( - Boolean useAsyncApi + bool useAsyncApi ) { var entity = this.CreateEntityInDb(); @@ -525,7 +525,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task QuerySingle_EntityType_EnumEntityProperty_ColumnContainsInvalidInteger_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => await Invoking(() => CallApi( useAsyncApi, @@ -550,7 +550,7 @@ await Invoking(() => CallApi( [InlineData(false)] [InlineData(true)] public async Task QuerySingle_EntityType_EnumEntityProperty_ColumnContainsInvalidString_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => await Invoking(() => CallApi( useAsyncApi, @@ -574,14 +574,14 @@ await Invoking(() => CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_EntityType_EnumEntityProperty_ShouldConvertIntegerToEnum(Boolean useAsyncApi) + public async Task QuerySingle_EntityType_EnumEntityProperty_ShouldConvertIntegerToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); (await CallApi( useAsyncApi, this.Connection, - $"SELECT 1 AS {Q("Id")}, {(Int32)enumValue} AS {Q("Enum")}", + $"SELECT 1 AS {Q("Id")}, {(int)enumValue} AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken )) .Enum @@ -591,7 +591,7 @@ public async Task QuerySingle_EntityType_EnumEntityProperty_ShouldConvertInteger [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_EntityType_EnumEntityProperty_ShouldConvertStringToEnum(Boolean useAsyncApi) + public async Task QuerySingle_EntityType_EnumEntityProperty_ShouldConvertStringToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); @@ -608,7 +608,7 @@ public async Task QuerySingle_EntityType_EnumEntityProperty_ShouldConvertStringT [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_EntityType_Mapping_Attributes_ShouldUseAttributesMapping(Boolean useAsyncApi) + public async Task QuerySingle_EntityType_Mapping_Attributes_ShouldUseAttributesMapping(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -620,7 +620,7 @@ public async Task QuerySingle_EntityType_Mapping_Attributes_ShouldUseAttributesM )) .Should().BeEquivalentTo( entity, - options => options.Using(context => context.Subject.Should().BeNull()) + options => options.Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -628,7 +628,7 @@ public async Task QuerySingle_EntityType_Mapping_Attributes_ShouldUseAttributesM [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_EntityType_Mapping_FluentApi_ShouldUseFluentApiMapping(Boolean useAsyncApi) + public async Task QuerySingle_EntityType_Mapping_FluentApi_ShouldUseFluentApiMapping(bool useAsyncApi) { MappingTestEntityFluentApi.Configure(); @@ -642,7 +642,7 @@ public async Task QuerySingle_EntityType_Mapping_FluentApi_ShouldUseFluentApiMap )) .Should().BeEquivalentTo( entity, - options => options.Using(context => context.Subject.Should().BeNull()) + options => options.Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -651,7 +651,7 @@ public async Task QuerySingle_EntityType_Mapping_FluentApi_ShouldUseFluentApiMap [InlineData(false)] [InlineData(true)] public Task QuerySingle_EntityType_NoCompatibleConstructor_NoParameterlessConstructor_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi(useAsyncApi, this.Connection, $"SELECT 1 AS {Q("NonExistent")}") @@ -670,7 +670,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QuerySingle_EntityType_NoCompatibleConstructor_PrivateParameterlessConstructor_ShouldUsePrivateConstructorAndProperties( - Boolean useAsyncApi + bool useAsyncApi ) { var entity = this.CreateEntityInDb(); @@ -689,7 +689,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QuerySingle_EntityType_NoCompatibleConstructor_PublicParameterlessConstructor_ShouldUsePublicConstructorAndProperties( - Boolean useAsyncApi + bool useAsyncApi ) { var entity = this.CreateEntityInDb(); @@ -706,7 +706,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_EntityType_NoMapping_ShouldUseEntityTypeNameAndPropertyNames(Boolean useAsyncApi) + public async Task QuerySingle_EntityType_NoMapping_ShouldUseEntityTypeNameAndPropertyNames(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -722,7 +722,7 @@ public async Task QuerySingle_EntityType_NoMapping_ShouldUseEntityTypeNameAndPro [Theory] [InlineData(false)] [InlineData(true)] - public Task QuerySingle_EntityType_NonNullableEntityProperty_ColumnContainsNull_ShouldThrow(Boolean useAsyncApi) + public Task QuerySingle_EntityType_NonNullableEntityProperty_ColumnContainsNull_ShouldThrow(bool useAsyncApi) { this.Connection.ExecuteNonQuery( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)" @@ -747,7 +747,7 @@ public Task QuerySingle_EntityType_NonNullableEntityProperty_ColumnContainsNull_ [InlineData(false)] [InlineData(true)] public async Task QuerySingle_EntityType_NullableEntityProperty_ColumnContainsNull_ShouldReturnNull( - Boolean useAsyncApi + bool useAsyncApi ) { await this.Connection.ExecuteNonQueryAsync( @@ -766,7 +766,7 @@ await this.Connection.ExecuteNonQueryAsync( [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_EntityType_ShouldSupportDateTimeOffsetValues(Boolean useAsyncApi) + public async Task QuerySingle_EntityType_ShouldSupportDateTimeOffsetValues(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); @@ -784,7 +784,7 @@ public async Task QuerySingle_EntityType_ShouldSupportDateTimeOffsetValues(Boole [Theory] [InlineData(false)] [InlineData(true)] - public Task QuerySingle_EntityType_UnsupportedFieldType_ShouldThrow(Boolean useAsyncApi) + public Task QuerySingle_EntityType_UnsupportedFieldType_ShouldThrow(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.HasUnsupportedDataType, ""); @@ -807,7 +807,7 @@ public Task QuerySingle_EntityType_UnsupportedFieldType_ShouldThrow(Boolean useA [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_InterpolatedParameter_ShouldPassInterpolatedParameter(Boolean useAsyncApi) + public async Task QuerySingle_InterpolatedParameter_ShouldPassInterpolatedParameter(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -823,7 +823,7 @@ public async Task QuerySingle_InterpolatedParameter_ShouldPassInterpolatedParame [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_Parameter_ShouldPassParameter(Boolean useAsyncApi) + public async Task QuerySingle_Parameter_ShouldPassParameter(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -844,7 +844,7 @@ public async Task QuerySingle_Parameter_ShouldPassParameter(Boolean useAsyncApi) [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_QueryReturnedMoreThanOneRow_ShouldThrow(Boolean useAsyncApi) + public async Task QuerySingle_QueryReturnedMoreThanOneRow_ShouldThrow(bool useAsyncApi) { this.CreateEntitiesInDb(2); @@ -864,7 +864,7 @@ await Invoking(() => CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public Task QuerySingle_QueryReturnedNoRows_ShouldThrow(Boolean useAsyncApi) => + public Task QuerySingle_QueryReturnedNoRows_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi( useAsyncApi, this.Connection, @@ -881,7 +881,7 @@ public Task QuerySingle_QueryReturnedNoRows_ShouldThrow(Boolean useAsyncApi) => [InlineData(false)] [InlineData(true)] public async Task - QuerySingle_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(Boolean useAsyncApi) + QuerySingle_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -892,7 +892,7 @@ public async Task var temporaryTableName = statement.TemporaryTables[0].Name; - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, statement, @@ -909,7 +909,7 @@ public async Task [InlineData(true)] public async Task QuerySingle_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -933,7 +933,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task QuerySingle_Transaction_ShouldUseTransaction(bool useAsyncApi) { await using (var transaction = await this.Connection.BeginTransactionAsync()) { @@ -966,7 +966,7 @@ await Invoking(() => CallApi( [InlineData(true)] public async Task QuerySingle_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthNotOne_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) @@ -974,7 +974,7 @@ Boolean useAsyncApi // Oracle doesn't allow to return an empty string, because it treats empty strings as NULLs. await Invoking(() => - CallApi>( + CallApi>( useAsyncApi, this.Connection, $"SELECT '' AS {Q("Value")}", @@ -984,18 +984,18 @@ await Invoking(() => .Should().ThrowAsync() .WithMessage( "The column 'Value' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(Char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + $"to the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string '' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } await Invoking(() => - CallApi>( + CallApi>( useAsyncApi, this.Connection, $"SELECT 'ab' AS {Q("Value")}", @@ -1005,12 +1005,12 @@ await Invoking(() => .Should().ThrowAsync() .WithMessage( "The column 'Value' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(Char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + $"to the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } @@ -1020,12 +1020,12 @@ await Invoking(() => [InlineData(true)] public async Task QuerySingle_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - Boolean useAsyncApi + bool useAsyncApi ) { - var character = Generate.Single(); + var character = Generate.Single(); - (await CallApi>( + (await CallApi>( useAsyncApi, this.Connection, $"SELECT '{character}'", @@ -1038,7 +1038,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task QuerySingle_ValueTupleType_ColumnDataTypeNotCompatibleWithValueTupleFieldType_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi>( @@ -1059,7 +1059,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task QuerySingle_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidInteger_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi>( @@ -1085,7 +1085,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task QuerySingle_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidString_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi>( @@ -1110,14 +1110,14 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_ValueTupleType_EnumValueTupleField_ShouldConvertIntegerToEnum(Boolean useAsyncApi) + public async Task QuerySingle_ValueTupleType_EnumValueTupleField_ShouldConvertIntegerToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); (await CallApi>( useAsyncApi, this.Connection, - $"SELECT {(Int32)enumValue}", + $"SELECT {(int)enumValue}", cancellationToken: TestContext.Current.CancellationToken )) .Should().Be(ValueTuple.Create(enumValue)); @@ -1126,7 +1126,7 @@ public async Task QuerySingle_ValueTupleType_EnumValueTupleField_ShouldConvertIn [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_ValueTupleType_EnumValueTupleField_ShouldConvertStringToEnum(Boolean useAsyncApi) + public async Task QuerySingle_ValueTupleType_EnumValueTupleField_ShouldConvertStringToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); @@ -1143,7 +1143,7 @@ public async Task QuerySingle_ValueTupleType_EnumValueTupleField_ShouldConvertSt [InlineData(false)] [InlineData(true)] public Task QuerySingle_ValueTupleType_NonNullableValueTupleField_ColumnContainsNull_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) { this.Connection.ExecuteNonQuery( @@ -1151,7 +1151,7 @@ Boolean useAsyncApi ); return Invoking(() => - CallApi>( + CallApi>( useAsyncApi, this.Connection, $"SELECT {Q("BooleanValue")} FROM {Q("Entity")}", @@ -1161,7 +1161,7 @@ Boolean useAsyncApi .Should().ThrowAsync() .WithMessage( "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + - $"corresponding field of the value tuple type {typeof(ValueTuple)} is non-nullable.*" + $"corresponding field of the value tuple type {typeof(ValueTuple)} is non-nullable.*" ); } @@ -1169,14 +1169,14 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task QuerySingle_ValueTupleType_NullableValueTupleField_ColumnContainsNull_ShouldReturnNull( - Boolean useAsyncApi + bool useAsyncApi ) { await this.Connection.ExecuteNonQueryAsync( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("NullableBooleanValue")}) VALUES(1, NULL)" ); - (await CallApi>( + (await CallApi>( useAsyncApi, this.Connection, $"SELECT {Q("NullableBooleanValue")} FROM {Q("Entity")}", @@ -1189,10 +1189,10 @@ await this.Connection.ExecuteNonQueryAsync( [InlineData(false)] [InlineData(true)] public Task QuerySingle_ValueTupleType_NumberOfColumnsDoesNotMatchNumberOfValueTupleFields_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => - CallApi<(Int32, Int32)>( + CallApi<(int, int)>( useAsyncApi, this.Connection, "SELECT 1", @@ -1201,7 +1201,7 @@ Boolean useAsyncApi ) .Should().ThrowAsync() .WithMessage( - $"The SQL statement returned 1 column, but the value tuple type {typeof((Int32, Int32))} has 2 " + + $"The SQL statement returned 1 column, but the value tuple type {typeof((int, int))} has 2 " + "fields. Make sure that the SQL statement returns the same number of columns as the number of " + "fields in the value tuple type.*" ); @@ -1209,11 +1209,11 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_ValueTupleType_ShouldMaterializeBinaryData(Boolean useAsyncApi) + public async Task QuerySingle_ValueTupleType_ShouldMaterializeBinaryData(bool useAsyncApi) { - var bytes = Generate.Single(); + var bytes = Generate.Single(); - (await CallApi>( + (await CallApi>( useAsyncApi, this.Connection, $"SELECT {Parameter(bytes)} AS BinaryData", @@ -1225,13 +1225,13 @@ public async Task QuerySingle_ValueTupleType_ShouldMaterializeBinaryData(Boolean [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_ValueTupleType_ShouldSupportDateTimeOffsetValues(Boolean useAsyncApi) + public async Task QuerySingle_ValueTupleType_ShouldSupportDateTimeOffsetValues(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); var entity = this.CreateEntityInDb(); - (await CallApi<(Int64 Id, DateTimeOffset DateTimeOffsetValue)>( + (await CallApi<(long Id, DateTimeOffset DateTimeOffsetValue)>( useAsyncApi, this.Connection, $"SELECT {Q("Id")}, {Q("DateTimeOffsetValue")} FROM {Q("EntityWithDateTimeOffset")}", @@ -1243,14 +1243,14 @@ public async Task QuerySingle_ValueTupleType_ShouldSupportDateTimeOffsetValues(B [Theory] [InlineData(false)] [InlineData(true)] - public Task QuerySingle_ValueTupleType_UnsupportedFieldType_ShouldThrow(Boolean useAsyncApi) + public Task QuerySingle_ValueTupleType_UnsupportedFieldType_ShouldThrow(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.HasUnsupportedDataType, ""); var literal = this.TestDatabaseProvider.GetUnsupportedDataTypeLiteral(); return Invoking(() => - CallApi>( + CallApi>( useAsyncApi, this.Connection, $"SELECT {literal} AS {Q("Value")}", @@ -1264,7 +1264,7 @@ public Task QuerySingle_ValueTupleType_UnsupportedFieldType_ShouldThrow(Boolean } private static Task CallApi( - Boolean useAsyncApi, + bool useAsyncApi, DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOrDefaultOfTTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOrDefaultOfTTests.cs index 9c36fb3..2264ded 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOrDefaultOfTTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOrDefaultOfTTests.cs @@ -32,7 +32,7 @@ public abstract class [InlineData(true)] public async Task QuerySingleOrDefault_BuiltInType_CharTargetType_ColumnContainsStringWithLengthNotOne_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) @@ -40,7 +40,7 @@ Boolean useAsyncApi // Oracle doesn't allow to return an empty string, because it treats empty strings as NULLs. (await Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT ''", @@ -49,18 +49,18 @@ Boolean useAsyncApi ) .Should().ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value '' ({typeof(String)}), " + - $"which could not be converted to the type {typeof(Char)}. See inner exception for details.*" + $"The first column returned by the SQL statement contains the value '' ({typeof(string)}), " + + $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" )) .WithInnerException() .WithMessage( - $"Could not convert the string '' to the type {typeof(Char)}. The string must be exactly " + + $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly " + "one character long." ); } (await Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT 'ab'", @@ -69,12 +69,12 @@ Boolean useAsyncApi ) .Should().ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value 'ab' ({typeof(String)}), " + - $"which could not be converted to the type {typeof(Char)}. See inner exception for details.*" + $"The first column returned by the SQL statement contains the value 'ab' ({typeof(string)}), " + + $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" )) .WithInnerException() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be exactly " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + "one character long." ); } @@ -84,12 +84,12 @@ Boolean useAsyncApi [InlineData(true)] public async Task QuerySingleOrDefault_BuiltInType_CharTargetType_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - Boolean useAsyncApi + bool useAsyncApi ) { - var character = Generate.Single(); + var character = Generate.Single(); - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, $"SELECT '{character}'", @@ -102,10 +102,10 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task QuerySingleOrDefault_BuiltInType_ColumnValueCannotBeConvertedToTargetType_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT 'A'", @@ -114,15 +114,15 @@ Boolean useAsyncApi ) .Should().ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value 'A' ({typeof(String)}), which " + - $"could not be converted to the type {typeof(Int32)}. See inner exception for details.*" + $"The first column returned by the SQL statement contains the value 'A' ({typeof(string)}), which " + + $"could not be converted to the type {typeof(int)}. See inner exception for details.*" ); [Theory] [InlineData(false)] [InlineData(true)] public Task QuerySingleOrDefault_BuiltInType_EnumTargetType_ColumnContainsInvalidInteger_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi( @@ -142,7 +142,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task QuerySingleOrDefault_BuiltInType_EnumTargetType_ColumnContainsInvalidString_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi( @@ -155,21 +155,21 @@ Boolean useAsyncApi .Should().ThrowAsync() .WithMessage( "The first column returned by the SQL statement contains the value 'NonExistent' " + - $"({typeof(String)}), which could not be converted to the type {typeof(TestEnum)}. See inner " + + $"({typeof(string)}), which could not be converted to the type {typeof(TestEnum)}. See inner " + "exception for details.*" ); [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_BuiltInType_EnumTargetType_ShouldConvertIntegerToEnum(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_BuiltInType_EnumTargetType_ShouldConvertIntegerToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); (await CallApi( useAsyncApi, this.Connection, - $"SELECT {(Int32)enumValue}", + $"SELECT {(int)enumValue}", cancellationToken: TestContext.Current.CancellationToken )) .Should().Be(enumValue); @@ -178,7 +178,7 @@ public async Task QuerySingleOrDefault_BuiltInType_EnumTargetType_ShouldConvertI [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_BuiltInType_EnumTargetType_ShouldConvertStringToEnum(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_BuiltInType_EnumTargetType_ShouldConvertStringToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); @@ -195,10 +195,10 @@ public async Task QuerySingleOrDefault_BuiltInType_EnumTargetType_ShouldConvertS [InlineData(false)] [InlineData(true)] public Task QuerySingleOrDefault_BuiltInType_NonNullableTargetType_ColumnContainsNull_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => - CallApi( + CallApi( useAsyncApi, this.Connection, "SELECT NULL", @@ -208,16 +208,16 @@ Boolean useAsyncApi .Should().ThrowAsync() .WithMessage( "The first column returned by the SQL statement contains a NULL value, which could not be converted " + - $"to the type {typeof(Int32)}. See inner exception for details.*" + $"to the type {typeof(int)}. See inner exception for details.*" ); [Theory] [InlineData(false)] [InlineData(true)] public async Task QuerySingleOrDefault_BuiltInType_NullableTargetType_ColumnContainsNull_ShouldReturnNull( - Boolean useAsyncApi + bool useAsyncApi ) => - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, "SELECT NULL", @@ -228,7 +228,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_BuiltInType_ShouldSupportDateTimeOffsetValues(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_BuiltInType_ShouldSupportDateTimeOffsetValues(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); @@ -247,7 +247,7 @@ public async Task QuerySingleOrDefault_BuiltInType_ShouldSupportDateTimeOffsetVa [InlineData(false)] [InlineData(true)] public async Task QuerySingleOrDefault_CancellationToken_ShouldCancelOperationIfCancellationIsRequested( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -271,7 +271,7 @@ await Invoking(() => [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_CommandType_ShouldUseCommandType(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_CommandType_ShouldUseCommandType(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsStoredProceduresReturningResultSet, ""); @@ -291,7 +291,7 @@ public async Task QuerySingleOrDefault_CommandType_ShouldUseCommandType(Boolean [InlineData(false)] [InlineData(true)] public async Task - QuerySingleOrDefault_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution(Boolean useAsyncApi) + QuerySingleOrDefault_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -318,7 +318,7 @@ public async Task [InlineData(true)] public async Task QuerySingleOrDefault_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -339,7 +339,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QuerySingleOrDefault_EntityType_CharEntityProperty_ColumnContainsStringWithLengthNotOne_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) @@ -357,12 +357,12 @@ await Invoking(() => .Should().ThrowAsync() .WithMessage( "The column 'CharValue' returned by the SQL statement contains a value that could not be " + - $"converted to the type {typeof(Char)} of the corresponding property of the type " + + $"converted to the type {typeof(char)} of the corresponding property of the type " + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string '' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } @@ -378,12 +378,12 @@ await Invoking(() => .Should().ThrowAsync() .WithMessage( "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(Char)} of the corresponding property of the type " + + $"to the type {typeof(char)} of the corresponding property of the type " + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } @@ -393,10 +393,10 @@ await Invoking(() => [InlineData(true)] public async Task QuerySingleOrDefault_EntityType_CharEntityProperty_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - Boolean useAsyncApi + bool useAsyncApi ) { - var character = Generate.Single(); + var character = Generate.Single(); (await CallApi( useAsyncApi, @@ -411,7 +411,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task QuerySingleOrDefault_EntityType_ColumnDataTypeNotCompatibleWithEntityPropertyType_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi( @@ -431,7 +431,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_EntityType_ColumnHasNoName_ShouldThrow(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_EntityType_ColumnHasNoName_ShouldThrow(bool useAsyncApi) { InterpolatedSqlStatement statement = this.TestDatabaseProvider switch { @@ -464,7 +464,7 @@ await Invoking(() => [InlineData(false)] [InlineData(true)] public async Task QuerySingleOrDefault_EntityType_CompatiblePrivateConstructor_ShouldUsePrivateConstructor( - Boolean useAsyncApi + bool useAsyncApi ) { var entity = this.CreateEntityInDb(); @@ -482,7 +482,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task QuerySingleOrDefault_EntityType_CompatiblePublicConstructor_ShouldUsePublicConstructor( - Boolean useAsyncApi + bool useAsyncApi ) { var entity = this.CreateEntityInDb(); @@ -501,7 +501,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QuerySingleOrDefault_EntityType_EntityTypeHasNoCorrespondingPropertyForColumn_ShouldIgnoreColumn( - Boolean useAsyncApi + bool useAsyncApi ) { var entity = (await Invoking(() => @@ -523,7 +523,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QuerySingleOrDefault_EntityType_EntityTypeWithPropertiesWithDifferentCasing_ShouldMaterializeEntities( - Boolean useAsyncApi + bool useAsyncApi ) { var entity = this.CreateEntityInDb(); @@ -543,7 +543,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QuerySingleOrDefault_EntityType_EnumEntityProperty_ColumnContainsInvalidInteger_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => await Invoking(() => CallApi( useAsyncApi, @@ -569,7 +569,7 @@ await Invoking(() => CallApi( [InlineData(true)] public async Task QuerySingleOrDefault_EntityType_EnumEntityProperty_ColumnContainsInvalidString_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => await Invoking(() => CallApi( useAsyncApi, @@ -593,14 +593,14 @@ await Invoking(() => CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_EntityType_EnumEntityProperty_ShouldConvertIntegerToEnum(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_EntityType_EnumEntityProperty_ShouldConvertIntegerToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); (await CallApi( useAsyncApi, this.Connection, - $"SELECT 1 AS {Q("Id")}, {(Int32)enumValue} AS {Q("Enum")}", + $"SELECT 1 AS {Q("Id")}, {(int)enumValue} AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken ))! .Enum @@ -610,7 +610,7 @@ public async Task QuerySingleOrDefault_EntityType_EnumEntityProperty_ShouldConve [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_EntityType_EnumEntityProperty_ShouldConvertStringToEnum(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_EntityType_EnumEntityProperty_ShouldConvertStringToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); @@ -627,7 +627,7 @@ public async Task QuerySingleOrDefault_EntityType_EnumEntityProperty_ShouldConve [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_EntityType_Mapping_Attributes_ShouldUseAttributesMapping(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_EntityType_Mapping_Attributes_ShouldUseAttributesMapping(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -639,7 +639,7 @@ public async Task QuerySingleOrDefault_EntityType_Mapping_Attributes_ShouldUseAt )) .Should().BeEquivalentTo( entity, - options => options.Using(context => context.Subject.Should().BeNull()) + options => options.Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -647,7 +647,7 @@ public async Task QuerySingleOrDefault_EntityType_Mapping_Attributes_ShouldUseAt [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_EntityType_Mapping_FluentApi_ShouldUseFluentApiMapping(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_EntityType_Mapping_FluentApi_ShouldUseFluentApiMapping(bool useAsyncApi) { MappingTestEntityFluentApi.Configure(); @@ -661,7 +661,7 @@ public async Task QuerySingleOrDefault_EntityType_Mapping_FluentApi_ShouldUseFlu )) .Should().BeEquivalentTo( entity, - options => options.Using(context => context.Subject.Should().BeNull()) + options => options.Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -670,7 +670,7 @@ public async Task QuerySingleOrDefault_EntityType_Mapping_FluentApi_ShouldUseFlu [InlineData(false)] [InlineData(true)] public Task QuerySingleOrDefault_EntityType_NoCompatibleConstructor_NoParameterlessConstructor_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi( @@ -693,7 +693,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QuerySingleOrDefault_EntityType_NoCompatibleConstructor_PrivateParameterlessConstructor_ShouldUsePrivateConstructorAndProperties( - Boolean useAsyncApi + bool useAsyncApi ) { var entity = this.CreateEntityInDb(); @@ -712,7 +712,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QuerySingleOrDefault_EntityType_NoCompatibleConstructor_PublicParameterlessConstructor_ShouldUsePublicConstructorAndProperties( - Boolean useAsyncApi + bool useAsyncApi ) { var entity = this.CreateEntityInDb(); @@ -730,7 +730,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task QuerySingleOrDefault_EntityType_NoMapping_ShouldUseEntityTypeNameAndPropertyNames( - Boolean useAsyncApi + bool useAsyncApi ) { var entity = this.CreateEntityInDb(); @@ -748,7 +748,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task QuerySingleOrDefault_EntityType_NonNullableEntityProperty_ColumnContainsNull_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) { this.Connection.ExecuteNonQuery( @@ -774,7 +774,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task QuerySingleOrDefault_EntityType_NullableEntityProperty_ColumnContainsNull_ShouldReturnNull( - Boolean useAsyncApi + bool useAsyncApi ) { await this.Connection.ExecuteNonQueryAsync( @@ -793,7 +793,7 @@ await this.Connection.ExecuteNonQueryAsync( [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_EntityType_ShouldSupportDateTimeOffsetValues(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_EntityType_ShouldSupportDateTimeOffsetValues(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); @@ -811,7 +811,7 @@ public async Task QuerySingleOrDefault_EntityType_ShouldSupportDateTimeOffsetVal [Theory] [InlineData(false)] [InlineData(true)] - public Task QuerySingleOrDefault_EntityType_UnsupportedFieldType_ShouldThrow(Boolean useAsyncApi) + public Task QuerySingleOrDefault_EntityType_UnsupportedFieldType_ShouldThrow(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.HasUnsupportedDataType, ""); @@ -834,7 +834,7 @@ public Task QuerySingleOrDefault_EntityType_UnsupportedFieldType_ShouldThrow(Boo [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_InterpolatedParameter_ShouldPassInterpolatedParameter(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_InterpolatedParameter_ShouldPassInterpolatedParameter(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -850,7 +850,7 @@ public async Task QuerySingleOrDefault_InterpolatedParameter_ShouldPassInterpola [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_Parameter_ShouldPassParameter(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_Parameter_ShouldPassParameter(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -871,7 +871,7 @@ public async Task QuerySingleOrDefault_Parameter_ShouldPassParameter(Boolean use [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_QueryReturnedMoreThanOneRow_ShouldThrow(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_QueryReturnedMoreThanOneRow_ShouldThrow(bool useAsyncApi) { this.CreateEntitiesInDb(2); @@ -891,9 +891,9 @@ await Invoking(() => CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_QueryReturnedNoRows_ShouldThrow(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_QueryReturnedNoRows_ShouldThrow(bool useAsyncApi) { - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("Id")} FROM {Q("Entity")} WHERE {Q("Id")} = -1", @@ -909,7 +909,7 @@ public async Task QuerySingleOrDefault_QueryReturnedNoRows_ShouldThrow(Boolean u )) .Should().BeNull(); - (await CallApi<(Int64, String)>( + (await CallApi<(long, string)>( useAsyncApi, this.Connection, $"SELECT {Q("Id")}, {Q("StringValue")} FROM {Q("Entity")} WHERE {Q("Id")} = -1", @@ -922,7 +922,7 @@ public async Task QuerySingleOrDefault_QueryReturnedNoRows_ShouldThrow(Boolean u [InlineData(false)] [InlineData(true)] public async Task - QuerySingleOrDefault_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(Boolean useAsyncApi) + QuerySingleOrDefault_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -933,7 +933,7 @@ public async Task var temporaryTableName = statement.TemporaryTables[0].Name; - (await CallApi( + (await CallApi( useAsyncApi, this.Connection, statement, @@ -950,7 +950,7 @@ public async Task [InlineData(true)] public async Task QuerySingleOrDefault_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -974,7 +974,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_Transaction_ShouldUseTransaction(bool useAsyncApi) { await using (var transaction = await this.Connection.BeginTransactionAsync()) { @@ -1006,7 +1006,7 @@ public async Task QuerySingleOrDefault_Transaction_ShouldUseTransaction(Boolean [InlineData(true)] public async Task QuerySingleOrDefault_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthNotOne_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) @@ -1014,7 +1014,7 @@ Boolean useAsyncApi // Oracle doesn't allow to return an empty string, because it treats empty strings as NULLs. await Invoking(() => - CallApi>( + CallApi>( useAsyncApi, this.Connection, $"SELECT '' AS {Q("Value")}", @@ -1024,18 +1024,18 @@ await Invoking(() => .Should().ThrowAsync() .WithMessage( "The column 'Value' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(Char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + $"to the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string '' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } await Invoking(() => - CallApi>( + CallApi>( useAsyncApi, this.Connection, $"SELECT 'ab' AS {Q("Value")}", @@ -1045,12 +1045,12 @@ await Invoking(() => .Should().ThrowAsync() .WithMessage( "The column 'Value' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(Char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + $"to the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + "exactly one character long." ); } @@ -1060,12 +1060,12 @@ await Invoking(() => [InlineData(true)] public async Task QuerySingleOrDefault_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - Boolean useAsyncApi + bool useAsyncApi ) { - var character = Generate.Single(); + var character = Generate.Single(); - (await CallApi>( + (await CallApi>( useAsyncApi, this.Connection, $"SELECT '{character}'", @@ -1079,7 +1079,7 @@ Boolean useAsyncApi [InlineData(true)] public Task QuerySingleOrDefault_ValueTupleType_ColumnDataTypeNotCompatibleWithValueTupleFieldType_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi>( @@ -1101,7 +1101,7 @@ Boolean useAsyncApi [InlineData(true)] public Task QuerySingleOrDefault_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidInteger_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi>( @@ -1128,7 +1128,7 @@ Boolean useAsyncApi [InlineData(true)] public Task QuerySingleOrDefault_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidString_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => CallApi>( @@ -1154,7 +1154,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task QuerySingleOrDefault_ValueTupleType_EnumValueTupleField_ShouldConvertIntegerToEnum( - Boolean useAsyncApi + bool useAsyncApi ) { var enumValue = Generate.Single(); @@ -1162,7 +1162,7 @@ Boolean useAsyncApi (await CallApi>( useAsyncApi, this.Connection, - $"SELECT {(Int32)enumValue}", + $"SELECT {(int)enumValue}", cancellationToken: TestContext.Current.CancellationToken )) .Should().Be(ValueTuple.Create(enumValue)); @@ -1172,7 +1172,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task QuerySingleOrDefault_ValueTupleType_EnumValueTupleField_ShouldConvertStringToEnum( - Boolean useAsyncApi + bool useAsyncApi ) { var enumValue = Generate.Single(); @@ -1190,7 +1190,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public Task QuerySingleOrDefault_ValueTupleType_NonNullableValueTupleField_ColumnContainsNull_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) { this.Connection.ExecuteNonQuery( @@ -1198,7 +1198,7 @@ Boolean useAsyncApi ); return Invoking(() => - CallApi>( + CallApi>( useAsyncApi, this.Connection, $"SELECT {Q("BooleanValue")} FROM {Q("Entity")}", @@ -1208,7 +1208,7 @@ Boolean useAsyncApi .Should().ThrowAsync() .WithMessage( "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + - $"corresponding field of the value tuple type {typeof(ValueTuple)} is non-nullable.*" + $"corresponding field of the value tuple type {typeof(ValueTuple)} is non-nullable.*" ); } @@ -1217,14 +1217,14 @@ Boolean useAsyncApi [InlineData(true)] public async Task QuerySingleOrDefault_ValueTupleType_NullableValueTupleField_ColumnContainsNull_ShouldReturnNull( - Boolean useAsyncApi + bool useAsyncApi ) { await this.Connection.ExecuteNonQueryAsync( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("NullableBooleanValue")}) VALUES(1, NULL)" ); - (await CallApi>( + (await CallApi>( useAsyncApi, this.Connection, $"SELECT {Q("NullableBooleanValue")} FROM {Q("Entity")}", @@ -1238,10 +1238,10 @@ await this.Connection.ExecuteNonQueryAsync( [InlineData(true)] public Task QuerySingleOrDefault_ValueTupleType_NumberOfColumnsDoesNotMatchNumberOfValueTupleFields_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) => Invoking(() => - CallApi<(Int32, Int32)>( + CallApi<(int, int)>( useAsyncApi, this.Connection, "SELECT 1", @@ -1250,7 +1250,7 @@ Boolean useAsyncApi ) .Should().ThrowAsync() .WithMessage( - $"The SQL statement returned 1 column, but the value tuple type {typeof((Int32, Int32))} has 2 " + + $"The SQL statement returned 1 column, but the value tuple type {typeof((int, int))} has 2 " + "fields. Make sure that the SQL statement returns the same number of columns as the number of " + "fields in the value tuple type.*" ); @@ -1258,11 +1258,11 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_ValueTupleType_ShouldMaterializeBinaryData(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_ValueTupleType_ShouldMaterializeBinaryData(bool useAsyncApi) { - var bytes = Generate.Single(); + var bytes = Generate.Single(); - (await CallApi>( + (await CallApi>( useAsyncApi, this.Connection, $"SELECT {Parameter(bytes)} AS BinaryData", @@ -1274,13 +1274,13 @@ public async Task QuerySingleOrDefault_ValueTupleType_ShouldMaterializeBinaryDat [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_ValueTupleType_ShouldSupportDateTimeOffsetValues(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_ValueTupleType_ShouldSupportDateTimeOffsetValues(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsDateTimeOffset, ""); var entity = this.CreateEntityInDb(); - (await CallApi<(Int64 Id, DateTimeOffset DateTimeOffsetValue)>( + (await CallApi<(long Id, DateTimeOffset DateTimeOffsetValue)>( useAsyncApi, this.Connection, $"SELECT {Q("Id")}, {Q("DateTimeOffsetValue")} FROM {Q("EntityWithDateTimeOffset")}", @@ -1292,14 +1292,14 @@ public async Task QuerySingleOrDefault_ValueTupleType_ShouldSupportDateTimeOffse [Theory] [InlineData(false)] [InlineData(true)] - public Task QuerySingleOrDefault_ValueTupleType_UnsupportedFieldType_ShouldThrow(Boolean useAsyncApi) + public Task QuerySingleOrDefault_ValueTupleType_UnsupportedFieldType_ShouldThrow(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.HasUnsupportedDataType, ""); var literal = this.TestDatabaseProvider.GetUnsupportedDataTypeLiteral(); return Invoking(() => - CallApi>( + CallApi>( useAsyncApi, this.Connection, $"SELECT {literal} AS {Q("Value")}", @@ -1313,7 +1313,7 @@ public Task QuerySingleOrDefault_ValueTupleType_UnsupportedFieldType_ShouldThrow } private static Task CallApi( - Boolean useAsyncApi, + bool useAsyncApi, DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOrDefaultTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOrDefaultTests.cs index 097c44b..92b0e9e 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOrDefaultTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOrDefaultTests.cs @@ -33,7 +33,7 @@ public abstract class [InlineData(false)] [InlineData(true)] public async Task QuerySingleOrDefault_CancellationToken_ShouldCancelOperationIfCancellationIsRequested( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -57,7 +57,7 @@ await Invoking(() => [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_CommandType_ShouldUseCommandType(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_CommandType_ShouldUseCommandType(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsStoredProceduresReturningResultSet, ""); @@ -78,7 +78,7 @@ public async Task QuerySingleOrDefault_CommandType_ShouldUseCommandType(Boolean [InlineData(false)] [InlineData(true)] public async Task QuerySingleOrDefault_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -107,7 +107,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QuerySingleOrDefault_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -127,7 +127,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_InterpolatedParameter_ShouldPassInterpolatedParameter(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_InterpolatedParameter_ShouldPassInterpolatedParameter(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -144,7 +144,7 @@ public async Task QuerySingleOrDefault_InterpolatedParameter_ShouldPassInterpola [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_Parameter_ShouldPassParameter(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_Parameter_ShouldPassParameter(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -166,7 +166,7 @@ public async Task QuerySingleOrDefault_Parameter_ShouldPassParameter(Boolean use [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_QueryReturnedMoreThanOneRow_ShouldThrow(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_QueryReturnedMoreThanOneRow_ShouldThrow(bool useAsyncApi) { this.CreateEntitiesInDb(2); @@ -187,8 +187,8 @@ await Invoking(() => CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_QueryReturnedNoRows_ShouldReturnNull(Boolean useAsyncApi) => - ((Object?)await CallApi( + public async Task QuerySingleOrDefault_QueryReturnedNoRows_ShouldReturnNull(bool useAsyncApi) => + ((object?)await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")} WHERE {Q("Id")} = -1", @@ -200,7 +200,7 @@ public async Task QuerySingleOrDefault_QueryReturnedNoRows_ShouldReturnNull(Bool [InlineData(false)] [InlineData(true)] public async Task QuerySingleOrDefault_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -233,7 +233,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QuerySingleOrDefault_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -247,14 +247,14 @@ Boolean useAsyncApi cancellationToken: TestContext.Current.CancellationToken ); - ValueConverter.ConvertValueToType(dataRow!["Id"]) + ValueConverter.ConvertValueToType(dataRow!["Id"]) .Should().Be(entityId); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_ShouldReturnDataRowForSingleRow(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_ShouldReturnDataRowForSingleRow(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -271,7 +271,7 @@ public async Task QuerySingleOrDefault_ShouldReturnDataRowForSingleRow(Boolean u [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingleOrDefault_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task QuerySingleOrDefault_Transaction_ShouldUseTransaction(bool useAsyncApi) { await using (var transaction = await this.Connection.BeginTransactionAsync()) { @@ -290,7 +290,7 @@ public async Task QuerySingleOrDefault_Transaction_ShouldUseTransaction(Boolean await transaction.RollbackAsync(); } - ((Object?)await CallApi( + ((object?)await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", @@ -300,7 +300,7 @@ public async Task QuerySingleOrDefault_Transaction_ShouldUseTransaction(Boolean } private static Task CallApi( - Boolean useAsyncApi, + bool useAsyncApi, DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleTests.cs index e56dc67..f65e3ff 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleTests.cs @@ -31,7 +31,7 @@ public abstract class [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(Boolean useAsyncApi) + public async Task QuerySingle_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -54,7 +54,7 @@ await Invoking(() => [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_CommandType_ShouldUseCommandType(Boolean useAsyncApi) + public async Task QuerySingle_CommandType_ShouldUseCommandType(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsStoredProceduresReturningResultSet, ""); @@ -75,7 +75,7 @@ public async Task QuerySingle_CommandType_ShouldUseCommandType(Boolean useAsyncA [InlineData(false)] [InlineData(true)] public async Task QuerySingle_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -104,7 +104,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task QuerySingle_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -124,7 +124,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_InterpolatedParameter_ShouldPassInterpolatedParameter(Boolean useAsyncApi) + public async Task QuerySingle_InterpolatedParameter_ShouldPassInterpolatedParameter(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -141,7 +141,7 @@ public async Task QuerySingle_InterpolatedParameter_ShouldPassInterpolatedParame [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_Parameter_ShouldPassParameter(Boolean useAsyncApi) + public async Task QuerySingle_Parameter_ShouldPassParameter(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -163,7 +163,7 @@ public async Task QuerySingle_Parameter_ShouldPassParameter(Boolean useAsyncApi) [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_QueryReturnedMoreThanOneRow_ShouldThrow(Boolean useAsyncApi) + public async Task QuerySingle_QueryReturnedMoreThanOneRow_ShouldThrow(bool useAsyncApi) { this.CreateEntitiesInDb(2); @@ -184,7 +184,7 @@ await Invoking(() => CallApi( [Theory] [InlineData(false)] [InlineData(true)] - public Task QuerySingle_QueryReturnedNoRows_ShouldThrow(Boolean useAsyncApi) => + public Task QuerySingle_QueryReturnedNoRows_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi( useAsyncApi, this.Connection, @@ -200,7 +200,7 @@ public Task QuerySingle_QueryReturnedNoRows_ShouldThrow(Boolean useAsyncApi) => [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(Boolean useAsyncApi) + public async Task QuerySingle_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -232,7 +232,7 @@ public async Task QuerySingle_ScalarValuesTemporaryTable_ShouldDropTemporaryTabl [InlineData(true)] public async Task QuerySingle_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -246,14 +246,14 @@ Boolean useAsyncApi cancellationToken: TestContext.Current.CancellationToken ); - ValueConverter.ConvertValueToType(dataRow["Id"]) + ValueConverter.ConvertValueToType(dataRow["Id"]) .Should().Be(entityId); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_ShouldReturnDataRowForSingleRow(Boolean useAsyncApi) + public async Task QuerySingle_ShouldReturnDataRowForSingleRow(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -270,7 +270,7 @@ public async Task QuerySingle_ShouldReturnDataRowForSingleRow(Boolean useAsyncAp [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task QuerySingle_Transaction_ShouldUseTransaction(bool useAsyncApi) { await using (var transaction = await this.Connection.BeginTransactionAsync()) { @@ -300,7 +300,7 @@ await Invoking(() => CallApi( } private static Task CallApi( - Boolean useAsyncApi, + bool useAsyncApi, DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryTests.cs index f058020..d6ebcee 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryTests.cs @@ -31,7 +31,7 @@ public abstract class [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(Boolean useAsyncApi) + public async Task Query_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -54,7 +54,7 @@ await Invoking(() => [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_CommandType_ShouldUseCommandType(Boolean useAsyncApi) + public async Task Query_CommandType_ShouldUseCommandType(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsStoredProceduresReturningResultSet, ""); @@ -75,7 +75,7 @@ public async Task Query_CommandType_ShouldUseCommandType(Boolean useAsyncApi) [InlineData(false)] [InlineData(true)] public async Task Query_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterEnumerationIsFinished( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -118,7 +118,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task Query_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -138,7 +138,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_InterpolatedParameter_ShouldPassInterpolatedParameter(Boolean useAsyncApi) + public async Task Query_InterpolatedParameter_ShouldPassInterpolatedParameter(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -155,7 +155,7 @@ public async Task Query_InterpolatedParameter_ShouldPassInterpolatedParameter(Bo [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_Parameter_ShouldPassParameter(Boolean useAsyncApi) + public async Task Query_Parameter_ShouldPassParameter(bool useAsyncApi) { var entity = this.CreateEntityInDb(); @@ -178,7 +178,7 @@ public async Task Query_Parameter_ShouldPassParameter(Boolean useAsyncApi) [InlineData(false)] [InlineData(true)] public async Task Query_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterEnumerationIsFinished( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -221,7 +221,7 @@ Boolean useAsyncApi [InlineData(false)] [InlineData(true)] public async Task Query_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - Boolean useAsyncApi + bool useAsyncApi ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -237,7 +237,7 @@ Boolean useAsyncApi for (var i = 0; i < entityIds.Count; i++) { - ValueConverter.ConvertValueToType(dataRows[i]["Id"]) + ValueConverter.ConvertValueToType(dataRows[i]["Id"]) .Should().Be(entityIds[i]); } } @@ -245,7 +245,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_ShouldReturnDataRowsForQueryResult(Boolean useAsyncApi) + public async Task Query_ShouldReturnDataRowsForQueryResult(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(); @@ -262,7 +262,7 @@ public async Task Query_ShouldReturnDataRowsForQueryResult(Boolean useAsyncApi) [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task Query_Transaction_ShouldUseTransaction(bool useAsyncApi) { await using (var transaction = await this.Connection.BeginTransactionAsync()) { @@ -291,7 +291,7 @@ public async Task Query_Transaction_ShouldUseTransaction(Boolean useAsyncApi) } private static IAsyncEnumerable CallApi( - Boolean useAsyncApi, + bool useAsyncApi, DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.TemporaryTableTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.TemporaryTableTests.cs index 1de3f5e..7f9e492 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.TemporaryTableTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.TemporaryTableTests.cs @@ -30,11 +30,11 @@ public void var entities = Generate.Multiple(); - this.Connection.Query( + this.Connection.Query( $"SELECT {Q("Enum")} FROM {TemporaryTable(entities)}", cancellationToken: TestContext.Current.CancellationToken ) - .Should().BeEquivalentTo(entities.Select(a => (Int32)a.Enum)); + .Should().BeEquivalentTo(entities.Select(a => (int)a.Enum)); } [Fact] @@ -46,7 +46,7 @@ public void TemporaryTable_ComplexObjects_EnumProperty_EnumSerializationModeIsSt var entities = Generate.Multiple(); - this.Connection.Query( + this.Connection.Query( $"SELECT {Q("Enum")} FROM {TemporaryTable(entities)}", cancellationToken: TestContext.Current.CancellationToken ) @@ -77,11 +77,11 @@ public void TemporaryTable_ScalarValues_Enums_EnumSerializationModeIsIntegers_Sh var enumValues = Generate.Multiple(); this.Connection - .Query( + .Query( $"SELECT {Q("Value")} FROM {TemporaryTable(enumValues)}", cancellationToken: TestContext.Current.CancellationToken ) - .Should().BeEquivalentTo(enumValues.Select(a => (Int32)a)); + .Should().BeEquivalentTo(enumValues.Select(a => (int)a)); } [Fact] @@ -94,7 +94,7 @@ public void TemporaryTable_ScalarValues_Enums_EnumSerializationModeIsStrings_Sho var enumValues = Generate.Multiple(); this.Connection - .Query( + .Query( $"SELECT {Q("Value")} FROM {TemporaryTable(enumValues)}", cancellationToken: TestContext.Current.CancellationToken ) @@ -109,7 +109,7 @@ public void TemporaryTable_ScalarValues_ShouldBePassedAsSingleColumnTemporaryTab var entityIds = Generate.Ids(); this.Connection - .Query( + .Query( $"SELECT {Q("Value")} FROM {TemporaryTable(entityIds)}", cancellationToken: TestContext.Current.CancellationToken ) @@ -126,11 +126,11 @@ public async Task var entities = Generate.Multiple(); - (await this.Connection.QueryAsync( + (await this.Connection.QueryAsync( $"SELECT {Q("Enum")} FROM {TemporaryTable(entities)}", cancellationToken: TestContext.Current.CancellationToken ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities.Select(a => (Int32)a.Enum)); + .Should().BeEquivalentTo(entities.Select(a => (int)a.Enum)); } [Fact] @@ -143,7 +143,7 @@ public async Task var entities = Generate.Multiple(); - (await this.Connection.QueryAsync( + (await this.Connection.QueryAsync( $"SELECT {Q("Enum")} FROM {TemporaryTable(entities)}", cancellationToken: TestContext.Current.CancellationToken ).ToListAsync(TestContext.Current.CancellationToken)) @@ -175,11 +175,11 @@ public async Task var enumValues = Generate.Multiple(); (await this.Connection - .QueryAsync( + .QueryAsync( $"SELECT {Q("Value")} FROM {TemporaryTable(enumValues)}", cancellationToken: TestContext.Current.CancellationToken ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(enumValues.Select(a => (Int32)a)); + .Should().BeEquivalentTo(enumValues.Select(a => (int)a)); } [Fact] @@ -193,7 +193,7 @@ public async Task var enumValues = Generate.Multiple(); (await this.Connection - .QueryAsync( + .QueryAsync( $"SELECT {Q("Value")} FROM {TemporaryTable(enumValues)}", cancellationToken: TestContext.Current.CancellationToken ).ToListAsync(TestContext.Current.CancellationToken)) @@ -208,7 +208,7 @@ public async Task TemporaryTableAsync_ScalarValues_ShouldBePassedAsSingleColumnT var entityIds = Generate.Ids(); (await this.Connection - .QueryAsync( + .QueryAsync( $"SELECT {Q("Value")} FROM {TemporaryTable(entityIds)}", cancellationToken: TestContext.Current.CancellationToken ).ToListAsync(TestContext.Current.CancellationToken)) diff --git a/tests/DbConnectionPlus.IntegrationTests/IntegrationTestsBase.cs b/tests/DbConnectionPlus.IntegrationTests/IntegrationTestsBase.cs index 55a7c0e..45a09ec 100644 --- a/tests/DbConnectionPlus.IntegrationTests/IntegrationTestsBase.cs +++ b/tests/DbConnectionPlus.IntegrationTests/IntegrationTestsBase.cs @@ -79,7 +79,7 @@ protected IntegrationTestsBase() /// DbConnectionPlus. Subsequent commands will not be delayed unless this property is set to /// again. /// - public Boolean DelayNextDbCommand { get; set; } + public bool DelayNextDbCommand { get; set; } /// public void Dispose() @@ -108,7 +108,7 @@ public async ValueTask DisposeAsync() /// The formatted parameter name, including the appropriate prefix, suitable for inclusion in SQL statements. /// /// The name of this method is intentionally kept very short, so test code doesn't get bloated. - public static String P(String parameterName) => + public static string P(string parameterName) => currentDatabaseAdapter.Value!.FormatParameterName(parameterName); /// @@ -118,7 +118,7 @@ public static String P(String parameterName) => /// The identifier to quote. /// The quoted identifier, suitable for inclusion in SQL statements. /// The name of this method is intentionally kept very short, so test code doesn't get bloated. - public static String Q(String identifier) => + public static string Q(string identifier) => currentDatabaseAdapter.Value!.QuoteIdentifier(identifier); /// @@ -128,7 +128,7 @@ public static String Q(String identifier) => /// The name of the temporary table to quote. /// The quoted temporary table name, suitable for inclusion in SQL statements. /// The name of this method is intentionally kept very short, so test code doesn't get bloated. - public static String QT(String tableName) => + public static string QT(string tableName) => currentDatabaseAdapter.Value!.QuoteTemporaryTableName( tableName, currentTestDatabaseConnection.Value! @@ -160,7 +160,7 @@ public static String QT(String tableName) => /// /// The database transaction within to perform the operation. /// The entities that were created and inserted. - protected List CreateEntitiesInDb(Int32? numberOfEntities = null, DbTransaction? transaction = null) + protected List CreateEntitiesInDb(int? numberOfEntities = null, DbTransaction? transaction = null) where T : class => this.ExecuteWithoutDbCommandLogging(() => { @@ -221,7 +221,7 @@ protected T CreateEntityInDb(DbTransaction? transaction = null) /// . /// /// - protected Boolean ExistsEntityInDb(T entity, DbTransaction? transaction = null) + protected bool ExistsEntityInDb(T entity, DbTransaction? transaction = null) where T : class { var metadata = EntityHelper.GetEntityTypeMetadata(typeof(T)); @@ -236,7 +236,7 @@ protected Boolean ExistsEntityInDb(T entity, DbTransaction? transaction = nul $""" SELECT 1 FROM {Q(metadata.TableName)} - WHERE {String.Join( + WHERE {string.Join( " AND ", keyProperties.Select(p => $"{Q(p.ColumnName)} = {P(p.PropertyName)}").ToList() )} @@ -261,7 +261,7 @@ SELECT 1 /// if a temporary table with the specified name exists in the test database; /// otherwise, . /// - protected Boolean ExistsTemporaryTableInDb(String tableName, DbTransaction? transaction = null) => + protected bool ExistsTemporaryTableInDb(string tableName, DbTransaction? transaction = null) => this.ExecuteWithoutDbCommandLogging(() => this.TestDatabaseProvider.ExistsTemporaryTable( tableName, @@ -276,7 +276,7 @@ protected Boolean ExistsTemporaryTableInDb(String tableName, DbTransaction? tran /// The name of the temporary table that contains the specified column. /// The name of the column of which to get the collation. /// The collation of the specified column of the specified temporary table. - protected String GetCollationOfTemporaryTableColumn(String temporaryTableName, String columnName) => + protected string GetCollationOfTemporaryTableColumn(string temporaryTableName, string columnName) => this.ExecuteWithoutDbCommandLogging(() => this.TestDatabaseProvider.GetCollationOfTemporaryTableColumn( temporaryTableName, @@ -291,9 +291,9 @@ protected String GetCollationOfTemporaryTableColumn(String temporaryTableName, S /// The name of the temporary table that contains the specified column. /// The name of the column of which to get the data type. /// The data type of the specified column of the specified temporary table. - protected String GetDataTypeOfTemporaryTableColumn( - String temporaryTableName, - String columnName + protected string GetDataTypeOfTemporaryTableColumn( + string temporaryTableName, + string columnName ) => this.ExecuteWithoutDbCommandLogging(() => this.TestDatabaseProvider.GetDataTypeOfTemporaryTableColumn( @@ -327,7 +327,7 @@ private void InterceptDbCommand(DbCommand command, IReadOnlyList /// The connection to the test database for the currently running integration test. diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/ITestDatabaseContainerFixture.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/ITestDatabaseContainerFixture.cs index cef66c9..4266f7f 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/ITestDatabaseContainerFixture.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/ITestDatabaseContainerFixture.cs @@ -15,5 +15,5 @@ internal interface ITestDatabaseContainerFixture : IAsyncLifetime /// The container publishes its port to a free port of the host, so this is only known once the container /// has been started. /// - public String ConnectionString { get; } + public string ConnectionString { get; } } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/MySqlContainerFixture.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/MySqlContainerFixture.cs index 0c7ebeb..f01390f 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/MySqlContainerFixture.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/MySqlContainerFixture.cs @@ -15,7 +15,7 @@ internal sealed class MySqlContainerFixture() : DbContainerFixture(TestDatabaseDiagnosticMessageSink.Instance), ITestDatabaseContainerFixture { /// - public override String ConnectionString => + public override string ConnectionString => new MySqlConnectionStringBuilder { Server = this.Container.Hostname, @@ -40,7 +40,7 @@ protected override MySqlBuilder Configure() => .WithUsername(RootUsername) .WithPassword(TestDatabaseContainers.Password); - private const String Image = "mysql:latest"; + private const string Image = "mysql:latest"; - private const String RootUsername = "root"; + private const string RootUsername = "root"; } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/OracleContainerFixture.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/OracleContainerFixture.cs index 05176cd..dd5ebfb 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/OracleContainerFixture.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/OracleContainerFixture.cs @@ -20,7 +20,7 @@ internal sealed class OracleContainerFixture() /// command-timeout tests call DBMS_LOCK.SLEEP, on which that user holds no EXECUTE grant. /// sets the password of both accounts. /// - public override String ConnectionString => + public override string ConnectionString => new OracleConnectionStringBuilder { DataSource = $"{this.Container.Hostname}:{this.MappedPort}/{ServiceName}", @@ -43,7 +43,7 @@ protected override OracleBuilder Configure() => /// /// The host port the container's Oracle listener is published on. /// - private UInt16 MappedPort => + private ushort MappedPort => this.Container.GetMappedPublicPort(OracleBuilder.OraclePort); /// @@ -54,9 +54,9 @@ protected override OracleBuilder Configure() => /// plain image spends several minutes creating FREEPDB1 on first start. The tag has to name the major /// version: the module reads it to decide that this image serves FREEPDB1 rather than XEPDB1. /// - private const String Image = "gvenzl/oracle-free:23-slim-faststart"; + private const string Image = "gvenzl/oracle-free:23-slim-faststart"; - private const String ServiceName = "FREEPDB1"; + private const string ServiceName = "FREEPDB1"; - private const String SystemUsername = "SYSTEM"; + private const string SystemUsername = "SYSTEM"; } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/PostgreSqlContainerFixture.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/PostgreSqlContainerFixture.cs index d8017a7..77c19a1 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/PostgreSqlContainerFixture.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/PostgreSqlContainerFixture.cs @@ -15,7 +15,7 @@ internal sealed class PostgreSqlContainerFixture() : DbContainerFixture(TestDatabaseDiagnosticMessageSink.Instance), ITestDatabaseContainerFixture { /// - public override String ConnectionString => + public override string ConnectionString => new NpgsqlConnectionStringBuilder { Host = this.Container.Hostname, @@ -33,5 +33,5 @@ protected override PostgreSqlBuilder Configure() => new PostgreSqlBuilder(Image) .WithPassword(TestDatabaseContainers.Password); - private const String Image = "postgres:latest"; + private const string Image = "postgres:latest"; } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/SqlServerContainerFixture.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/SqlServerContainerFixture.cs index 6fbf037..471dd5f 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/SqlServerContainerFixture.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/SqlServerContainerFixture.cs @@ -14,7 +14,7 @@ internal sealed class SqlServerContainerFixture() : DbContainerFixture(TestDatabaseDiagnosticMessageSink.Instance), ITestDatabaseContainerFixture { /// - public override String ConnectionString => + public override string ConnectionString => new SqlConnectionStringBuilder { DataSource = $"{this.Container.Hostname},{this.Container.GetMappedPublicPort(MsSqlBuilder.MsSqlPort)}", @@ -38,5 +38,5 @@ protected override MsSqlBuilder Configure() => new MsSqlBuilder(Image) .WithPassword(TestDatabaseContainers.Password); - private const String Image = "mcr.microsoft.com/mssql/server:2022-latest"; + private const string Image = "mcr.microsoft.com/mssql/server:2022-latest"; } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainer.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainer.cs index 06a9481..438ce07 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainer.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainer.cs @@ -16,7 +16,7 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.TestDatabase.Containe /// and SQL Server never starts the MySQL, Oracle or PostgreSQL containers. Sharing is what keeps it to one /// container per database system - every test class asks for the same instance. /// -internal sealed class TestDatabaseContainer(String databaseSystemName) +internal sealed class TestDatabaseContainer(string databaseSystemName) where TFixture : class, ITestDatabaseContainerFixture, new() { /// @@ -57,7 +57,7 @@ public async ValueTask DisposeAsync() public ValueTask StartAsync() => new(this.fixture.Value); - private static async Task CreateAndStartAsync(String databaseSystemName) + private static async Task CreateAndStartAsync(string databaseSystemName) { TestContext.Current.SendDiagnosticMessage($"Starting the {databaseSystemName} container ..."); diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainers.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainers.cs index fc03274..c38d66c 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainers.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainers.cs @@ -17,7 +17,7 @@ internal static class TestDatabaseContainers /// /// The password of the administrative database user in every container. /// - public const String Password = "TestTest123!"; + public const string Password = "TestTest123!"; /// /// The container running the MySQL server. diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseDiagnosticMessageSink.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseDiagnosticMessageSink.cs index 9101483..be4a02e 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseDiagnosticMessageSink.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseDiagnosticMessageSink.cs @@ -26,7 +26,7 @@ internal sealed class TestDatabaseDiagnosticMessageSink : IMessageSink public static readonly TestDatabaseDiagnosticMessageSink Instance = new(); /// - public Boolean OnMessage(IMessageSinkMessage message) + public bool OnMessage(IMessageSinkMessage message) { if (message is IDiagnosticMessage diagnosticMessage) { diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/ITestDatabaseProvider.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/ITestDatabaseProvider.cs index e72537a..feef808 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/ITestDatabaseProvider.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/ITestDatabaseProvider.cs @@ -11,7 +11,7 @@ public interface ITestDatabaseProvider /// /// Determines whether the structure of temporary tables can be retrieved from the test database system. /// - public Boolean CanRetrieveStructureOfTemporaryTables { get; } + public bool CanRetrieveStructureOfTemporaryTables { get; } /// /// The database adapter for the test database. @@ -21,50 +21,50 @@ public interface ITestDatabaseProvider /// /// The collation of the test database. /// - public String DatabaseCollation { get; } + public string DatabaseCollation { get; } /// /// An SQL statement that delays query execution for two seconds. /// - public String DelayTwoSecondsStatement { get; } + public string DelayTwoSecondsStatement { get; } /// /// Determines whether the test database system has data types not supported by DbConnectionPlus. /// - public Boolean HasUnsupportedDataType { get; } + public bool HasUnsupportedDataType { get; } /// /// Determines whether the test database system supports executing commands while a data reader is open. /// - public Boolean SupportsCommandExecutionWhileDataReaderIsOpen { get; } + public bool SupportsCommandExecutionWhileDataReaderIsOpen { get; } /// /// Determines whether the test database system has a data type for the type . /// - public Boolean SupportsDateTimeOffset { get; } + public bool SupportsDateTimeOffset { get; } /// /// Determines whether the test database system supports proper command cancellation, meaning that cancelling a /// command (via ) actually stops its execution in the database and an appropriate /// exception is thrown. /// - public Boolean SupportsProperCommandCancellation { get; } + public bool SupportsProperCommandCancellation { get; } /// /// Determines whether the test database system supports stored procedures. /// - public Boolean SupportsStoredProcedures { get; } + public bool SupportsStoredProcedures { get; } /// /// Determines whether the test database system supports stored procedures which can return a result set. /// - public Boolean SupportsStoredProceduresReturningResultSet { get; } + public bool SupportsStoredProceduresReturningResultSet { get; } /// /// Determines whether a text column of a temporary table in the test database system inherits the collation /// from the current database. /// - public Boolean TemporaryTableTextColumnInheritsCollationFromDatabase { get; } + public bool TemporaryTableTextColumnInheritsCollationFromDatabase { get; } /// /// Creates a connection to the test database. @@ -81,7 +81,7 @@ public interface ITestDatabaseProvider /// if a temporary table with the specified name exists in the test database; /// otherwise, . /// - public Boolean ExistsTemporaryTable(String tableName, DbConnection connection, DbTransaction? transaction = null); + public bool ExistsTemporaryTable(string tableName, DbConnection connection, DbTransaction? transaction = null); /// /// Gets the collation of the specified column in the specified temporary table. @@ -90,9 +90,9 @@ public interface ITestDatabaseProvider /// The name of the column whose collation to retrieve. /// The connection to the test database. /// The collation of the specified column in the specified temporary table. - public String GetCollationOfTemporaryTableColumn( - String temporaryTableName, - String columnName, + public string GetCollationOfTemporaryTableColumn( + string temporaryTableName, + string columnName, DbConnection connection ); @@ -105,9 +105,9 @@ DbConnection connection /// /// The data type of the specified column in the specified temporary table. /// - public String GetDataTypeOfTemporaryTableColumn( - String temporaryTableName, - String columnName, + public string GetDataTypeOfTemporaryTableColumn( + string temporaryTableName, + string columnName, DbConnection connection ); @@ -117,7 +117,7 @@ DbConnection connection /// /// A literal representing a data type in the test database system that is not supported by DbConnectionPlus. /// - public String GetUnsupportedDataTypeLiteral(); + public string GetUnsupportedDataTypeLiteral(); /// /// Prepares the test database and resets it to a clean state. diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/MySqlTestDatabaseProvider.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/MySqlTestDatabaseProvider.cs index e730661..cbcc1d3 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/MySqlTestDatabaseProvider.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/MySqlTestDatabaseProvider.cs @@ -12,37 +12,37 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.TestDatabase; public class MySqlTestDatabaseProvider : ITestDatabaseProvider { /// - public Boolean CanRetrieveStructureOfTemporaryTables => true; + public bool CanRetrieveStructureOfTemporaryTables => true; /// public IDatabaseAdapter DatabaseAdapter => new MySqlDatabaseAdapter(); /// - public String DatabaseCollation => throw new NotImplementedException(); + public string DatabaseCollation => throw new NotImplementedException(); /// - public String DelayTwoSecondsStatement => "SELECT SLEEP(2);"; + public string DelayTwoSecondsStatement => "SELECT SLEEP(2);"; /// - public Boolean HasUnsupportedDataType => false; + public bool HasUnsupportedDataType => false; /// - public Boolean SupportsCommandExecutionWhileDataReaderIsOpen => false; + public bool SupportsCommandExecutionWhileDataReaderIsOpen => false; /// - public Boolean SupportsDateTimeOffset => false; + public bool SupportsDateTimeOffset => false; /// - public Boolean SupportsProperCommandCancellation => false; + public bool SupportsProperCommandCancellation => false; /// - public Boolean SupportsStoredProcedures => true; + public bool SupportsStoredProcedures => true; /// - public Boolean SupportsStoredProceduresReturningResultSet => true; + public bool SupportsStoredProceduresReturningResultSet => true; /// - public Boolean TemporaryTableTextColumnInheritsCollationFromDatabase => true; + public bool TemporaryTableTextColumnInheritsCollationFromDatabase => true; /// public DbConnection CreateConnection() @@ -59,7 +59,7 @@ public DbConnection CreateConnection() } /// - public Boolean ExistsTemporaryTable(String tableName, DbConnection connection, DbTransaction? transaction = null) + public bool ExistsTemporaryTable(string tableName, DbConnection connection, DbTransaction? transaction = null) { try { @@ -80,26 +80,26 @@ public Boolean ExistsTemporaryTable(String tableName, DbConnection connection, D } /// - public String GetCollationOfTemporaryTableColumn( - String temporaryTableName, - String columnName, + public string GetCollationOfTemporaryTableColumn( + string temporaryTableName, + string columnName, DbConnection connection ) => throw new NotImplementedException(); /// - public String GetDataTypeOfTemporaryTableColumn( - String temporaryTableName, - String columnName, + public string GetDataTypeOfTemporaryTableColumn( + string temporaryTableName, + string columnName, DbConnection connection ) => - connection.Query<(String Field, String Type, String Null, String Key, Object Default, Object Extra)>( + connection.Query<(string Field, string Type, string Null, string Key, object Default, object Extra)>( $"SHOW COLUMNS FROM `{temporaryTableName}` WHERE Field = '{columnName}'", cancellationToken: TestContext.Current.CancellationToken ).Select(a => a.Type.ToUpper()).First(); /// - public String GetUnsupportedDataTypeLiteral() => + public string GetUnsupportedDataTypeLiteral() => throw new NotImplementedException(); /// @@ -131,14 +131,14 @@ public static ValueTask StartDatabaseAsync() => /// /// The connection string that connects to the MySQL server running in the test container. /// - private static String ConnectionString => + private static string ConnectionString => TestDatabaseContainers.MySql.ConnectionString; - private static void ExecuteScript(MySqlConnection connection, String script) + private static void ExecuteScript(MySqlConnection connection, string script) { var statements = script .Split("GO", StringSplitOptions.RemoveEmptyEntries) - .Where(a => !String.IsNullOrWhiteSpace(a.Trim())); + .Where(a => !string.IsNullOrWhiteSpace(a.Trim())); foreach (var statement in statements) { @@ -146,7 +146,7 @@ private static void ExecuteScript(MySqlConnection connection, String script) } } - private const String CreateDatabaseObjectsSql = + private const string CreateDatabaseObjectsSql = """ CREATE TABLE `Entity` ( @@ -252,9 +252,9 @@ FOR EACH ROW GO """; - private const String DatabaseName = "DbConnectionPlusTests"; + private const string DatabaseName = "DbConnectionPlusTests"; - private const String PurgeTablesSql = + private const string PurgeTablesSql = """ TRUNCATE TABLE `Entity`; GO @@ -269,5 +269,5 @@ FOR EACH ROW GO """; - private static Boolean isDatabasePrepared; + private static bool isDatabasePrepared; } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/OracleTestDatabaseProvider.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/OracleTestDatabaseProvider.cs index 157d683..3af4ff3 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/OracleTestDatabaseProvider.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/OracleTestDatabaseProvider.cs @@ -12,37 +12,37 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.TestDatabase; public class OracleTestDatabaseProvider : ITestDatabaseProvider { /// - public Boolean CanRetrieveStructureOfTemporaryTables => false; + public bool CanRetrieveStructureOfTemporaryTables => false; /// public IDatabaseAdapter DatabaseAdapter => new OracleDatabaseAdapter(); /// - public String DatabaseCollation => throw new NotImplementedException(); + public string DatabaseCollation => throw new NotImplementedException(); /// - public String DelayTwoSecondsStatement => "BEGIN DBMS_LOCK.SLEEP(2); END;"; + public string DelayTwoSecondsStatement => "BEGIN DBMS_LOCK.SLEEP(2); END;"; /// - public Boolean HasUnsupportedDataType => false; + public bool HasUnsupportedDataType => false; /// - public Boolean SupportsCommandExecutionWhileDataReaderIsOpen => true; + public bool SupportsCommandExecutionWhileDataReaderIsOpen => true; /// - public Boolean SupportsDateTimeOffset => true; + public bool SupportsDateTimeOffset => true; /// - public Boolean SupportsProperCommandCancellation => false; + public bool SupportsProperCommandCancellation => false; /// - public Boolean SupportsStoredProcedures => true; + public bool SupportsStoredProcedures => true; /// - public Boolean SupportsStoredProceduresReturningResultSet => false; + public bool SupportsStoredProceduresReturningResultSet => false; /// - public Boolean TemporaryTableTextColumnInheritsCollationFromDatabase => true; + public bool TemporaryTableTextColumnInheritsCollationFromDatabase => true; /// public DbConnection CreateConnection() @@ -58,7 +58,7 @@ public DbConnection CreateConnection() } /// - public Boolean ExistsTemporaryTable(String tableName, DbConnection connection, DbTransaction? transaction = null) + public bool ExistsTemporaryTable(string tableName, DbConnection connection, DbTransaction? transaction = null) { var quoteTemporaryTableName = this.DatabaseAdapter.QuoteTemporaryTableName(tableName, connection); var unquotedTemporaryTableName = quoteTemporaryTableName[1..^1]; // Strip the quotes ("). @@ -69,23 +69,23 @@ public Boolean ExistsTemporaryTable(String tableName, DbConnection connection, D } /// - public String GetCollationOfTemporaryTableColumn( - String temporaryTableName, - String columnName, + public string GetCollationOfTemporaryTableColumn( + string temporaryTableName, + string columnName, DbConnection connection ) => throw new NotImplementedException(); /// - public String GetDataTypeOfTemporaryTableColumn( - String temporaryTableName, - String columnName, + public string GetDataTypeOfTemporaryTableColumn( + string temporaryTableName, + string columnName, DbConnection connection ) => throw new NotImplementedException(); /// - public String GetUnsupportedDataTypeLiteral() => + public string GetUnsupportedDataTypeLiteral() => throw new NotImplementedException(); /// @@ -112,14 +112,14 @@ public static ValueTask StartDatabaseAsync() => /// /// The connection string that connects to the Oracle server running in the test container. /// - private static String ConnectionString => + private static string ConnectionString => TestDatabaseContainers.Oracle.ConnectionString; - private static void ExecuteScript(OracleConnection connection, String script) + private static void ExecuteScript(OracleConnection connection, string script) { var statements = script .Split("GO", StringSplitOptions.RemoveEmptyEntries) - .Where(a => !String.IsNullOrWhiteSpace(a.Trim())); + .Where(a => !string.IsNullOrWhiteSpace(a.Trim())); foreach (var statement in statements) { @@ -127,7 +127,7 @@ private static void ExecuteScript(OracleConnection connection, String script) } } - private const String CreateDatabaseObjectsSql = + private const string CreateDatabaseObjectsSql = """ CREATE TABLE "Entity" ( @@ -204,7 +204,7 @@ CREATE OR REPLACE NONEDITIONABLE PROCEDURE "DeleteAllEntities" AS """; - private const String DropDatabaseObjectsSql = + private const string DropDatabaseObjectsSql = """ DROP TABLE IF EXISTS "Entity" PURGE; GO @@ -225,7 +225,7 @@ CREATE OR REPLACE NONEDITIONABLE PROCEDURE "DeleteAllEntities" AS GO """; - private const String PurgeTablesSql = + private const string PurgeTablesSql = """ TRUNCATE TABLE "Entity"; GO @@ -243,5 +243,5 @@ CREATE OR REPLACE NONEDITIONABLE PROCEDURE "DeleteAllEntities" AS GO """; - private static Boolean isDatabasePrepared; + private static bool isDatabasePrepared; } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/PostgreSqlTestDatabaseProvider.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/PostgreSqlTestDatabaseProvider.cs index 684b6f4..c18e4c8 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/PostgreSqlTestDatabaseProvider.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/PostgreSqlTestDatabaseProvider.cs @@ -12,37 +12,37 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.TestDatabase; public class PostgreSqlTestDatabaseProvider : ITestDatabaseProvider { /// - public Boolean CanRetrieveStructureOfTemporaryTables => true; + public bool CanRetrieveStructureOfTemporaryTables => true; /// public IDatabaseAdapter DatabaseAdapter => new PostgreSqlDatabaseAdapter(); /// - public String DatabaseCollation => throw new NotImplementedException(); + public string DatabaseCollation => throw new NotImplementedException(); /// - public String DelayTwoSecondsStatement => "SELECT pg_sleep(2);"; + public string DelayTwoSecondsStatement => "SELECT pg_sleep(2);"; /// - public Boolean HasUnsupportedDataType => true; + public bool HasUnsupportedDataType => true; /// - public Boolean SupportsCommandExecutionWhileDataReaderIsOpen => false; + public bool SupportsCommandExecutionWhileDataReaderIsOpen => false; /// - public Boolean SupportsDateTimeOffset => false; + public bool SupportsDateTimeOffset => false; /// - public Boolean SupportsProperCommandCancellation => true; + public bool SupportsProperCommandCancellation => true; /// - public Boolean SupportsStoredProcedures => true; + public bool SupportsStoredProcedures => true; /// - public Boolean SupportsStoredProceduresReturningResultSet => false; + public bool SupportsStoredProceduresReturningResultSet => false; /// - public Boolean TemporaryTableTextColumnInheritsCollationFromDatabase => true; + public bool TemporaryTableTextColumnInheritsCollationFromDatabase => true; /// public DbConnection CreateConnection() @@ -54,7 +54,7 @@ public DbConnection CreateConnection() } /// - public Boolean ExistsTemporaryTable(String tableName, DbConnection connection, DbTransaction? transaction = null) => + public bool ExistsTemporaryTable(string tableName, DbConnection connection, DbTransaction? transaction = null) => connection.Exists( $""" SELECT 1 @@ -67,20 +67,20 @@ FROM information_schema.tables ); /// - public String GetCollationOfTemporaryTableColumn( - String temporaryTableName, - String columnName, + public string GetCollationOfTemporaryTableColumn( + string temporaryTableName, + string columnName, DbConnection connection ) => throw new NotImplementedException(); /// - public String GetDataTypeOfTemporaryTableColumn( - String temporaryTableName, - String columnName, + public string GetDataTypeOfTemporaryTableColumn( + string temporaryTableName, + string columnName, DbConnection connection ) => - connection.QuerySingle( + connection.QuerySingle( $""" SELECT data_type FROM information_schema.columns @@ -92,7 +92,7 @@ WHERE table_schema LIKE 'pg_temp%' AND ); /// - public String GetUnsupportedDataTypeLiteral() => + public string GetUnsupportedDataTypeLiteral() => "(1, 2)"; public void ResetDatabase() @@ -123,10 +123,10 @@ public static ValueTask StartDatabaseAsync() => /// /// The connection string that connects to the PostgreSQL server running in the test container. /// - private static String ConnectionString => + private static string ConnectionString => TestDatabaseContainers.PostgreSql.ConnectionString; - private const String CreateDatabaseObjectsSql = + private const string CreateDatabaseObjectsSql = """ CREATE EXTENSION IF NOT EXISTS pgcrypto; -- Needed for gen_random_bytes() @@ -228,9 +228,9 @@ DELETE FROM "Entity" $$; """; - private const String DatabaseName = "DbConnectionPlusTests"; + private const string DatabaseName = "DbConnectionPlusTests"; - private const String PurgeTablesSql = + private const string PurgeTablesSql = """ TRUNCATE TABLE "Entity"; TRUNCATE TABLE "EntityWithEnumStoredAsString"; @@ -238,5 +238,5 @@ DELETE FROM "Entity" TRUNCATE TABLE "MappingTestEntity"; """; - private static Boolean isDatabasePrepared; + private static bool isDatabasePrepared; } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SQLiteTestDatabaseProvider.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SQLiteTestDatabaseProvider.cs index 0efe85b..80b8cb3 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SQLiteTestDatabaseProvider.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SQLiteTestDatabaseProvider.cs @@ -22,16 +22,16 @@ public SqliteTestDatabaseProvider() } /// - public Boolean CanRetrieveStructureOfTemporaryTables => true; + public bool CanRetrieveStructureOfTemporaryTables => true; /// public IDatabaseAdapter DatabaseAdapter => new SqliteDatabaseAdapter(); /// - public String DatabaseCollation => throw new NotImplementedException(); + public string DatabaseCollation => throw new NotImplementedException(); /// - public String DelayTwoSecondsStatement => + public string DelayTwoSecondsStatement => """ WITH RECURSIVE delay(x) AS ( SELECT 1 @@ -42,32 +42,32 @@ SELECT x + 1 FROM delay WHERE x < 5000000 """; /// - public Boolean HasUnsupportedDataType => false; + public bool HasUnsupportedDataType => false; /// - public Boolean SupportsCommandExecutionWhileDataReaderIsOpen => true; + public bool SupportsCommandExecutionWhileDataReaderIsOpen => true; /// - public Boolean SupportsDateTimeOffset => true; + public bool SupportsDateTimeOffset => true; /// - public Boolean SupportsProperCommandCancellation => false; + public bool SupportsProperCommandCancellation => false; /// - public Boolean SupportsStoredProcedures => false; + public bool SupportsStoredProcedures => false; /// - public Boolean SupportsStoredProceduresReturningResultSet => false; + public bool SupportsStoredProceduresReturningResultSet => false; /// - public Boolean TemporaryTableTextColumnInheritsCollationFromDatabase => true; + public bool TemporaryTableTextColumnInheritsCollationFromDatabase => true; /// public DbConnection CreateConnection() => this.connection; /// - public Boolean ExistsTemporaryTable(String tableName, DbConnection connection, DbTransaction? transaction = null) => + public bool ExistsTemporaryTable(string tableName, DbConnection connection, DbTransaction? transaction = null) => this.connection.Exists( $""" SELECT 1 @@ -80,21 +80,21 @@ FROM sqlite_temp_master ); /// - public String GetCollationOfTemporaryTableColumn( - String temporaryTableName, - String columnName, + public string GetCollationOfTemporaryTableColumn( + string temporaryTableName, + string columnName, DbConnection connection ) => throw new NotImplementedException(); /// - public String GetDataTypeOfTemporaryTableColumn( - String temporaryTableName, - String columnName, + public string GetDataTypeOfTemporaryTableColumn( + string temporaryTableName, + string columnName, DbConnection connection ) => this.connection - .Query<(Int32 cid, String name, String Type, Boolean notnull, Object dflt_value, Int32 pk)>( + .Query<(int cid, string name, string Type, bool notnull, object dflt_value, int pk)>( $""" PRAGMA table_info("{temporaryTableName}"); """, @@ -105,7 +105,7 @@ DbConnection connection .Single(); /// - public String GetUnsupportedDataTypeLiteral() => + public string GetUnsupportedDataTypeLiteral() => throw new NotImplementedException(); /// @@ -126,9 +126,9 @@ public static ValueTask StartDatabaseAsync() => private readonly SqliteConnection connection; - private Boolean isDatabasePrepared; + private bool isDatabasePrepared; - private const String CreateDatabaseObjectsSql = + private const string CreateDatabaseObjectsSql = """ CREATE TABLE Entity ( diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SqlServerTestDatabaseProvider.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SqlServerTestDatabaseProvider.cs index 299f67a..db62ed9 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SqlServerTestDatabaseProvider.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SqlServerTestDatabaseProvider.cs @@ -11,37 +11,37 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.TestDatabase; public class SqlServerTestDatabaseProvider : ITestDatabaseProvider { /// - public Boolean CanRetrieveStructureOfTemporaryTables => true; + public bool CanRetrieveStructureOfTemporaryTables => true; /// public IDatabaseAdapter DatabaseAdapter => new SqlServerDatabaseAdapter(); /// - public String DatabaseCollation => "Latin1_General_CI_AS"; + public string DatabaseCollation => "Latin1_General_CI_AS"; /// - public String DelayTwoSecondsStatement => "WAITFOR DELAY '00:00:02';"; + public string DelayTwoSecondsStatement => "WAITFOR DELAY '00:00:02';"; /// - public Boolean HasUnsupportedDataType => true; + public bool HasUnsupportedDataType => true; /// - public Boolean SupportsCommandExecutionWhileDataReaderIsOpen => true; + public bool SupportsCommandExecutionWhileDataReaderIsOpen => true; /// - public Boolean SupportsDateTimeOffset => true; + public bool SupportsDateTimeOffset => true; /// - public Boolean SupportsProperCommandCancellation => true; + public bool SupportsProperCommandCancellation => true; /// - public Boolean SupportsStoredProcedures => true; + public bool SupportsStoredProcedures => true; /// - public Boolean SupportsStoredProceduresReturningResultSet => true; + public bool SupportsStoredProceduresReturningResultSet => true; /// - public Boolean TemporaryTableTextColumnInheritsCollationFromDatabase => false; + public bool TemporaryTableTextColumnInheritsCollationFromDatabase => false; /// public DbConnection CreateConnection() @@ -55,20 +55,20 @@ public DbConnection CreateConnection() } /// - public Boolean ExistsTemporaryTable(String tableName, DbConnection connection, DbTransaction? transaction = null) => - connection.ExecuteScalar( + public bool ExistsTemporaryTable(string tableName, DbConnection connection, DbTransaction? transaction = null) => + connection.ExecuteScalar( $"IF OBJECT_ID('tempdb..#{tableName}', 'U') IS NOT NULL SELECT 1 ELSE SELECT 0", transaction, cancellationToken: TestContext.Current.CancellationToken ); /// - public String GetCollationOfTemporaryTableColumn( - String temporaryTableName, - String columnName, + public string GetCollationOfTemporaryTableColumn( + string temporaryTableName, + string columnName, DbConnection connection ) => - connection.ExecuteScalar( + connection.ExecuteScalar( $""" SELECT C.collation_name AS CollationName FROM tempdb.sys.columns C @@ -78,12 +78,12 @@ FROM tempdb.sys.columns C ); /// - public String GetDataTypeOfTemporaryTableColumn( - String temporaryTableName, - String columnName, + public string GetDataTypeOfTemporaryTableColumn( + string temporaryTableName, + string columnName, DbConnection connection ) => - connection.QuerySingle( + connection.QuerySingle( $""" SELECT t.name AS DataType FROM tempdb.sys.columns c @@ -94,7 +94,7 @@ FROM tempdb.sys.columns c ); /// - public String GetUnsupportedDataTypeLiteral() => + public string GetUnsupportedDataTypeLiteral() => "CONVERT(SQL_VARIANT, 123)"; /// @@ -136,14 +136,14 @@ public static ValueTask StartDatabaseAsync() => /// /// The connection string that connects to the SQL Server server running in the test container. /// - private static String ConnectionString => + private static string ConnectionString => TestDatabaseContainers.SqlServer.ConnectionString; - private static void ExecuteScript(SqlConnection connection, String script) + private static void ExecuteScript(SqlConnection connection, string script) { var statements = script .Split("GO", StringSplitOptions.RemoveEmptyEntries) - .Where(a => !String.IsNullOrWhiteSpace(a.Trim())); + .Where(a => !string.IsNullOrWhiteSpace(a.Trim())); foreach (var statement in statements) { @@ -151,7 +151,7 @@ private static void ExecuteScript(SqlConnection connection, String script) } } - private const String CreateDatabaseObjectsSql = + private const string CreateDatabaseObjectsSql = """ CREATE TABLE Entity ( @@ -255,9 +255,9 @@ DELETE FROM Entity GO """; - private const String DatabaseName = "DbConnectionPlusTests"; + private const string DatabaseName = "DbConnectionPlusTests"; - private const String PurgeTablesSql = + private const string PurgeTablesSql = """ TRUNCATE TABLE Entity; GO @@ -275,5 +275,5 @@ DELETE FROM Entity GO """; - private static Boolean isDatabasePrepared; + private static bool isDatabasePrepared; } diff --git a/tests/DbConnectionPlus.UnitTests/Assertions/DecoratorAssertions.cs b/tests/DbConnectionPlus.UnitTests/Assertions/DecoratorAssertions.cs index 5fe303a..7a98f2f 100644 --- a/tests/DbConnectionPlus.UnitTests/Assertions/DecoratorAssertions.cs +++ b/tests/DbConnectionPlus.UnitTests/Assertions/DecoratorAssertions.cs @@ -29,7 +29,7 @@ public static void AssertDecoratorForwardsAllCalls( Fixture fixture, TDecorator decorator, TDecorator decorated, - HashSet excludedMethods + HashSet excludedMethods ) where TDecorator : class { @@ -45,7 +45,7 @@ HashSet excludedMethods { var methodParameters = method.GetParameters(); - var decoratorMethodArguments = new Object?[methodParameters.Length]; + var decoratorMethodArguments = new object?[methodParameters.Length]; for (var i = 0; i < methodParameters.Length; i++) { @@ -64,7 +64,7 @@ HashSet excludedMethods } } - Object? decoratedMethodReturnValue = null; + object? decoratedMethodReturnValue = null; if (method.ReturnType != typeof(void)) { diff --git a/tests/DbConnectionPlus.UnitTests/Configuration/DbConnectionPlusConfigurationTests.cs b/tests/DbConnectionPlus.UnitTests/Configuration/DbConnectionPlusConfigurationTests.cs index 5afe39a..36730b3 100644 --- a/tests/DbConnectionPlus.UnitTests/Configuration/DbConnectionPlusConfigurationTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Configuration/DbConnectionPlusConfigurationTests.cs @@ -32,7 +32,7 @@ public void EnumSerializationMode_Integers_ShouldSerializeEnumAsInteger() .Should().NotBeNull(); interceptedDbParameter.Value - .Should().Be((Int32)enumValue); + .Should().Be((int)enumValue); } [Fact] @@ -213,7 +213,7 @@ WHERE TEntity.Id IN ({TemporaryTable(entityIds)}) OR StringValue = {Parameter(s var timeout = Generate.Single(); var cancellationToken = Generate.Single(); - _ = this.MockDbConnection.Query( + _ = this.MockDbConnection.Query( statement, transaction, timeout, @@ -245,7 +245,7 @@ WHERE TEntity.Id IN ([#{temporaryTables[1].Name}]) OR StringValue = @StringValu .Should().Be(CommandType.StoredProcedure); interceptedDbCommand.CommandTimeout - .Should().Be((Int32)timeout.TotalSeconds); + .Should().Be((int)timeout.TotalSeconds); interceptedDbCommand.Parameters.Count .Should().Be(1); diff --git a/tests/DbConnectionPlus.UnitTests/Converters/EnumConverterTests.cs b/tests/DbConnectionPlus.UnitTests/Converters/EnumConverterTests.cs index 8e96c4c..f64884d 100644 --- a/tests/DbConnectionPlus.UnitTests/Converters/EnumConverterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Converters/EnumConverterTests.cs @@ -6,7 +6,7 @@ public class EnumConverterTests : UnitTestsBase { [Fact] public void ConvertValueToEnumMember_EmptyStringValue_ShouldThrow() => - Invoking(() => EnumConverter.ConvertValueToEnumMember(String.Empty, typeof(TestEnum))) + Invoking(() => EnumConverter.ConvertValueToEnumMember(string.Empty, typeof(TestEnum))) .Should().Throw() .WithMessage( "Could not convert an empty string or a string that consists only of white-space characters to an " + @@ -16,18 +16,18 @@ public void ConvertValueToEnumMember_EmptyStringValue_ShouldThrow() => [Fact] public void ConvertValueToEnumMember_NonEnumTargetType_ShouldThrow() { - Invoking(() => EnumConverter.ConvertValueToEnumMember("ValueA", typeof(Int32))) + Invoking(() => EnumConverter.ConvertValueToEnumMember("ValueA", typeof(int))) .Should().Throw() .WithMessage( - $"Could not convert the value 'ValueA' ({typeof(String)}) to an enum member of the type " + - $"{typeof(Int32)}, because the type {typeof(Int32)} is not an enum type.*" + $"Could not convert the value 'ValueA' ({typeof(string)}) to an enum member of the type " + + $"{typeof(int)}, because the type {typeof(int)} is not an enum type.*" ); - Invoking(() => EnumConverter.ConvertValueToEnumMember("ValueA", typeof(Int32?))) + Invoking(() => EnumConverter.ConvertValueToEnumMember("ValueA", typeof(int?))) .Should().Throw() .WithMessage( - $"Could not convert the value 'ValueA' ({typeof(String)}) to an enum member of the type " + - $"{typeof(Int32?)}, because the type {typeof(Int32?)} is not an enum type.*" + $"Could not convert the value 'ValueA' ({typeof(string)}) to an enum member of the type " + + $"{typeof(int?)}, because the type {typeof(int?)} is not an enum type.*" ); } @@ -62,14 +62,14 @@ public void ConvertValueToEnumMember_NumericValueNotMatchingAnyEnumMemberValue_S Invoking(() => EnumConverter.ConvertValueToEnumMember(999, typeof(TestEnum))) .Should().Throw() .WithMessage( - $"Could not convert the value '999' ({typeof(Int32)}) to an enum member of the type " + + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members." ); [Theory] [MemberData(nameof(GetConvertValueToEnumMemberTestData))] public void - ConvertValueToEnumMember_ShouldConvertValueToEnumMember(Object value, TestEnum expectedResult) + ConvertValueToEnumMember_ShouldConvertValueToEnumMember(object value, TestEnum expectedResult) { EnumConverter.ConvertValueToEnumMember(value, typeof(TestEnum)) .Should().Be(expectedResult); @@ -118,7 +118,7 @@ public void ConvertValueToEnumMember_WhitespaceStringValue_ShouldThrow() => [Fact] public void ConvertValueToEnumMemberOfT_EmptyStringValue_ShouldThrow() => - Invoking(() => EnumConverter.ConvertValueToEnumMember(String.Empty)) + Invoking(() => EnumConverter.ConvertValueToEnumMember(string.Empty)) .Should().Throw() .WithMessage( "Could not convert an empty string or a string that consists only of white-space characters to an " + @@ -128,18 +128,18 @@ public void ConvertValueToEnumMemberOfT_EmptyStringValue_ShouldThrow() => [Fact] public void ConvertValueToEnumMemberOfT_NonEnumTargetType_ShouldThrow() { - Invoking(() => EnumConverter.ConvertValueToEnumMember("ValueA")) + Invoking(() => EnumConverter.ConvertValueToEnumMember("ValueA")) .Should().Throw() .WithMessage( - $"Could not convert the value 'ValueA' ({typeof(String)}) to an enum member of the type " + - $"{typeof(Int32)}, because the type {typeof(Int32)} is not an enum type.*" + $"Could not convert the value 'ValueA' ({typeof(string)}) to an enum member of the type " + + $"{typeof(int)}, because the type {typeof(int)} is not an enum type.*" ); - Invoking(() => EnumConverter.ConvertValueToEnumMember("ValueA")) + Invoking(() => EnumConverter.ConvertValueToEnumMember("ValueA")) .Should().Throw() .WithMessage( - $"Could not convert the value 'ValueA' ({typeof(String)}) to an enum member of the type " + - $"{typeof(Int32?)}, because the type {typeof(Int32?)} is not an enum type.*" + $"Could not convert the value 'ValueA' ({typeof(string)}) to an enum member of the type " + + $"{typeof(int?)}, because the type {typeof(int?)} is not an enum type.*" ); } @@ -174,14 +174,14 @@ public void ConvertValueToEnumMemberOfT_NumericValueNotMatchingAnyEnumMemberValu Invoking(() => EnumConverter.ConvertValueToEnumMember(999)) .Should().Throw() .WithMessage( - $"Could not convert the value '999' ({typeof(Int32)}) to an enum member of the type " + + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members." ); [Theory] [MemberData(nameof(GetConvertValueToEnumMemberTestData))] public void - ConvertValueToEnumMemberOfT_ShouldConvertValueToEnumMember(Object value, TestEnum expectedResult) + ConvertValueToEnumMemberOfT_ShouldConvertValueToEnumMember(object value, TestEnum expectedResult) { EnumConverter.ConvertValueToEnumMember(value) .Should().Be(expectedResult); @@ -228,13 +228,13 @@ public void ConvertValueToEnumMemberOfT_WhitespaceStringValue_ShouldThrow() => $"enum member of the type {typeof(TestEnum)}." ); - public static IEnumerable<(Object value, TestEnum expectedResult)> GetConvertValueToEnumMemberTestData() => + public static IEnumerable<(object value, TestEnum expectedResult)> GetConvertValueToEnumMemberTestData() => [ - ((Int16)1, TestEnum.Value1), - ((Int16)2, TestEnum.Value2), - ((Int16)3, TestEnum.Value3), - ((Int16)4, TestEnum.Value4), - ((Int16)5, TestEnum.Value5), + ((short)1, TestEnum.Value1), + ((short)2, TestEnum.Value2), + ((short)3, TestEnum.Value3), + ((short)4, TestEnum.Value4), + ((short)5, TestEnum.Value5), (1, TestEnum.Value1), (2, TestEnum.Value2), (3, TestEnum.Value3), @@ -245,26 +245,26 @@ public void ConvertValueToEnumMemberOfT_WhitespaceStringValue_ShouldThrow() => (3L, TestEnum.Value3), (4L, TestEnum.Value4), (5L, TestEnum.Value5), - ((Byte)1, TestEnum.Value1), - ((Byte)2, TestEnum.Value2), - ((Byte)3, TestEnum.Value3), - ((Byte)4, TestEnum.Value4), - ((Byte)5, TestEnum.Value5), - ((Single)1.0, TestEnum.Value1), - ((Single)2.0, TestEnum.Value2), - ((Single)3.0, TestEnum.Value3), - ((Single)4.0, TestEnum.Value4), - ((Single)5.0, TestEnum.Value5), + ((byte)1, TestEnum.Value1), + ((byte)2, TestEnum.Value2), + ((byte)3, TestEnum.Value3), + ((byte)4, TestEnum.Value4), + ((byte)5, TestEnum.Value5), + ((float)1.0, TestEnum.Value1), + ((float)2.0, TestEnum.Value2), + ((float)3.0, TestEnum.Value3), + ((float)4.0, TestEnum.Value4), + ((float)5.0, TestEnum.Value5), (1.0, TestEnum.Value1), (2.0, TestEnum.Value2), (3.0, TestEnum.Value3), (4.0, TestEnum.Value4), (5.0, TestEnum.Value5), - ((Decimal)1.0, TestEnum.Value1), - ((Decimal)2.0, TestEnum.Value2), - ((Decimal)3.0, TestEnum.Value3), - ((Decimal)4.0, TestEnum.Value4), - ((Decimal)5.0, TestEnum.Value5), + ((decimal)1.0, TestEnum.Value1), + ((decimal)2.0, TestEnum.Value2), + ((decimal)3.0, TestEnum.Value3), + ((decimal)4.0, TestEnum.Value4), + ((decimal)5.0, TestEnum.Value5), ("Value1", TestEnum.Value1), ("Value2", TestEnum.Value2), ("Value3", TestEnum.Value3), diff --git a/tests/DbConnectionPlus.UnitTests/Converters/EnumSerializerTests.cs b/tests/DbConnectionPlus.UnitTests/Converters/EnumSerializerTests.cs index 648e58d..7faf6db 100644 --- a/tests/DbConnectionPlus.UnitTests/Converters/EnumSerializerTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Converters/EnumSerializerTests.cs @@ -26,7 +26,7 @@ public void SerializeEnum_InvalidEnumSerializationMode_ShouldThrow() => public void SerializeEnum_ShouldSerializeEnumValueAccordingToSerializationMode( TestEnum enumValue, EnumSerializationMode enumSerializationMode, - Object expectedResult + object expectedResult ) => EnumSerializer.SerializeEnum(enumValue, enumSerializationMode) .Should().Be(expectedResult); diff --git a/tests/DbConnectionPlus.UnitTests/Converters/ValueConverterTests.cs b/tests/DbConnectionPlus.UnitTests/Converters/ValueConverterTests.cs index 9ba8097..d9e54f6 100644 --- a/tests/DbConnectionPlus.UnitTests/Converters/ValueConverterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Converters/ValueConverterTests.cs @@ -19,9 +19,9 @@ public class ValueConverterTests : UnitTestsBase public void CanConvert_NullableSourceType_ShouldDetermineIfConversionIsPossible( Type sourceType, Type targetType, - Boolean expectedCanConvert, - Object? sourceValue, - Object? expectedTargetValue + bool expectedCanConvert, + object? sourceValue, + object? expectedTargetValue ) { Assert.SkipUnless(sourceType.IsValueType, ""); @@ -43,9 +43,9 @@ public void CanConvert_NullableSourceType_ShouldDetermineIfConversionIsPossible( public void CanConvert_NullableTargetType_ShouldDetermineIfConversionIsPossible( Type sourceType, Type targetType, - Boolean expectedCanConvert, - Object? sourceValue, - Object? expectedTargetValue + bool expectedCanConvert, + object? sourceValue, + object? expectedTargetValue ) { Assert.SkipUnless(targetType.IsValueType, ""); @@ -67,11 +67,11 @@ public void CanConvert_NullableTargetType_ShouldDetermineIfConversionIsPossible( public void CanConvert_ShouldDetermineIfConversionIsPossible( Type sourceType, Type targetType, - Boolean expectedCanConvert, + bool expectedCanConvert, #pragma warning disable xUnit1026 // Theory methods should use all of their parameters #pragma warning disable RCS1163 // Unused parameter - Object? sourceValue, - Object? expectedTargetValue + object? sourceValue, + object? expectedTargetValue #pragma warning restore RCS1163 // Unused parameter #pragma warning restore xUnit1026 // Theory methods should use all of their parameters ) => @@ -84,43 +84,43 @@ public void CanConvert_ShouldDetermineIfConversionIsPossible( [Fact] public void ConvertValueToType_CharTargetType_StringWithLengthOneValue_ShouldGetFirstCharacter() { - var character = Generate.Single(); + var character = Generate.Single(); - ValueConverter.ConvertValueToType(character.ToString(), typeof(Char)) + ValueConverter.ConvertValueToType(character.ToString(), typeof(char)) .Should().Be(character); - ValueConverter.ConvertValueToType(character.ToString(), typeof(Char?)) + ValueConverter.ConvertValueToType(character.ToString(), typeof(char?)) .Should().Be(character); } [Fact] public void ConvertValueToType_CharTargetType_ValueIsStringWithLengthNotOne_ShouldThrow() { - Invoking(() => ValueConverter.ConvertValueToType(String.Empty, typeof(Char))) + Invoking(() => ValueConverter.ConvertValueToType(string.Empty, typeof(char))) .Should().Throw() .WithMessage( - $"Could not convert the string '' to the type {typeof(Char)}. The string must be exactly one " + + $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly one " + "character long." ); - Invoking(() => ValueConverter.ConvertValueToType(String.Empty, typeof(Char?))) + Invoking(() => ValueConverter.ConvertValueToType(string.Empty, typeof(char?))) .Should().Throw() .WithMessage( - $"Could not convert the string '' to the type {typeof(Char?)}. The string must be exactly one " + + $"Could not convert the string '' to the type {typeof(char?)}. The string must be exactly one " + "character long." ); - Invoking(() => ValueConverter.ConvertValueToType("ab", typeof(Char))) + Invoking(() => ValueConverter.ConvertValueToType("ab", typeof(char))) .Should().Throw() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be exactly one " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly one " + "character long." ); - Invoking(() => ValueConverter.ConvertValueToType("ab", typeof(Char?))) + Invoking(() => ValueConverter.ConvertValueToType("ab", typeof(char?))) .Should().Throw() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char?)}. The string must be exactly one " + + $"Could not convert the string 'ab' to the type {typeof(char?)}. The string must be exactly one " + "character long." ); } @@ -130,7 +130,7 @@ public void ConvertValueToType_CharTargetType_ValueIsStringWithLengthNotOne_Shou [InlineData("fr-FR")] [InlineData("en-US")] public void ConvertValueToType_DateAndTimeStringValue_AmbiguousDate_ShouldNotDependOnTheCurrentCulture( - String cultureName + string cultureName ) { // "03/04/2026" is the 4th of March under en-US and the 3rd of April under de-DE and fr-FR. Read with @@ -152,7 +152,7 @@ String cultureName [InlineData("de-DE")] [InlineData("fr-FR")] [InlineData("en-US")] - public void ConvertValueToType_DateAndTimeStringValue_ShouldRoundTripUnderAnyCulture(String cultureName) + public void ConvertValueToType_DateAndTimeStringValue_ShouldRoundTripUnderAnyCulture(string cultureName) { // The converter writes these four types with the invariant culture, so it has to read them back the // same way. It did not: under a culture whose decimal separator is a comma, a TimeSpan this library @@ -174,7 +174,7 @@ public void ConvertValueToType_DateAndTimeStringValue_ShouldRoundTripUnderAnyCul // assertion is that the writing half and the reading half agree - not that either matches a literal. static void AssertRoundTrips(TValue value) { - var text = ValueConverter.ConvertValueToType(value); + var text = ValueConverter.ConvertValueToType(value); ValueConverter.ConvertValueToType(text) .Should().Be(value, $"{typeof(TValue)} written as '{text}' should read back unchanged"); @@ -191,14 +191,14 @@ public void Invoking(() => ValueConverter.ConvertValueToType(999, typeof(TestEnum))) .Should().Throw() .WithMessage( - $"Could not convert the value '999' ({typeof(Int32)}) to an enum member of the type " + + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); Invoking(() => ValueConverter.ConvertValueToType(999, typeof(TestEnum?))) .Should().Throw() .WithMessage( - $"Could not convert the value '999' ({typeof(Int32)}) to an enum member of the type " + + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + $"{typeof(TestEnum?)}. That value does not match any of the values of the enum's members.*" ); } @@ -208,10 +208,10 @@ public void ConvertValueToType_EnumTargetType_ShouldConvertToEnumMember() { var enumValue = Generate.Single(); - ValueConverter.ConvertValueToType((Int32)enumValue, typeof(TestEnum)) + ValueConverter.ConvertValueToType((int)enumValue, typeof(TestEnum)) .Should().Be(enumValue); - ValueConverter.ConvertValueToType((Int32)enumValue, typeof(TestEnum?)) + ValueConverter.ConvertValueToType((int)enumValue, typeof(TestEnum?)) .Should().Be(enumValue); } @@ -257,9 +257,9 @@ public void ConvertValueToType_NonNullableTargetType_NullOrDBNullValue_ShouldThr public void ConvertValueToType_NullableSourceType_ShouldConvertValueToTargetType( Type sourceType, Type targetType, - Boolean expectedCanConvert, - Object? sourceValue, - Object? expectedTargetValue + bool expectedCanConvert, + object? sourceValue, + object? expectedTargetValue ) { Assert.SkipUnless(sourceType.IsValueType, ""); @@ -279,16 +279,16 @@ public void ConvertValueToType_NullableSourceType_ShouldConvertValueToTargetType [Fact] public void ConvertValueToType_NullableTargetType_NullOrDBNullValue_ShouldReturnNull() { - ValueConverter.ConvertValueToType(DBNull.Value, typeof(Object)) + ValueConverter.ConvertValueToType(DBNull.Value, typeof(object)) .Should().BeNull(); - ValueConverter.ConvertValueToType(DBNull.Value, typeof(Int32?)) + ValueConverter.ConvertValueToType(DBNull.Value, typeof(int?)) .Should().BeNull(); - ValueConverter.ConvertValueToType(null, typeof(Object)) + ValueConverter.ConvertValueToType(null, typeof(object)) .Should().BeNull(); - ValueConverter.ConvertValueToType(null, typeof(Int32?)) + ValueConverter.ConvertValueToType(null, typeof(int?)) .Should().BeNull(); } @@ -297,9 +297,9 @@ public void ConvertValueToType_NullableTargetType_NullOrDBNullValue_ShouldReturn public void ConvertValueToType_NullableTargetType_ShouldConvertValueToTargetType( Type sourceType, Type targetType, - Boolean expectedCanConvert, - Object? sourceValue, - Object? expectedTargetValue + bool expectedCanConvert, + object? sourceValue, + object? expectedTargetValue ) { Assert.SkipUnless(targetType.IsValueType, ""); @@ -321,16 +321,16 @@ public void ConvertValueToType_NullableTargetType_ShouldConvertValueToTargetType public void ConvertValueToType_ShouldConvertValueToType( Type _, Type targetType, - Boolean expectedCanConvert, - Object? sourceValue, - Object? expectedTargetValue + bool expectedCanConvert, + object? sourceValue, + object? expectedTargetValue ) { if (expectedCanConvert) { var result = ValueConverter.ConvertValueToType(sourceValue, targetType); - if (result is Byte[] resultBytes && expectedTargetValue is Byte[] expectedTargetValueBytes) + if (result is byte[] resultBytes && expectedTargetValue is byte[] expectedTargetValueBytes) { resultBytes .Should().BeEquivalentTo( @@ -364,7 +364,7 @@ public void ConvertValueToType_ValueCannotBeConvertedToTargetType_ShouldThrow() Invoking(() => ValueConverter.ConvertValueToType("NotADate", typeof(DateTime))) .Should().Throw() .WithMessage( - $"Could not convert the value 'NotADate' ({typeof(String)}) to the type {typeof(DateTime)}. See " + + $"Could not convert the value 'NotADate' ({typeof(string)}) to the type {typeof(DateTime)}. See " + "inner exception for details.*" ) .WithInnerException() @@ -373,43 +373,43 @@ public void ConvertValueToType_ValueCannotBeConvertedToTargetType_ShouldThrow() [Fact] public void ConvertValueToTypeOfT_CharTargetType_StringWithLengthOneValue_ShouldGetFirstCharacter() { - var character = Generate.Single(); + var character = Generate.Single(); - ValueConverter.ConvertValueToType(character.ToString()) + ValueConverter.ConvertValueToType(character.ToString()) .Should().Be(character); - ValueConverter.ConvertValueToType(character.ToString()) + ValueConverter.ConvertValueToType(character.ToString()) .Should().Be(character); } [Fact] public void ConvertValueToTypeOfT_CharTargetType_ValueIsStringWithLengthNotOne_ShouldThrow() { - Invoking(() => ValueConverter.ConvertValueToType(String.Empty)) + Invoking(() => ValueConverter.ConvertValueToType(string.Empty)) .Should().Throw() .WithMessage( - $"Could not convert the string '' to the type {typeof(Char)}. The string must be exactly one " + + $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly one " + "character long." ); - Invoking(() => ValueConverter.ConvertValueToType(String.Empty)) + Invoking(() => ValueConverter.ConvertValueToType(string.Empty)) .Should().Throw() .WithMessage( - $"Could not convert the string '' to the type {typeof(Char?)}. The string must be exactly one " + + $"Could not convert the string '' to the type {typeof(char?)}. The string must be exactly one " + "character long." ); - Invoking(() => ValueConverter.ConvertValueToType("ab")) + Invoking(() => ValueConverter.ConvertValueToType("ab")) .Should().Throw() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be exactly one " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly one " + "character long." ); - Invoking(() => ValueConverter.ConvertValueToType("ab")) + Invoking(() => ValueConverter.ConvertValueToType("ab")) .Should().Throw() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char?)}. The string must be exactly one " + + $"Could not convert the string 'ab' to the type {typeof(char?)}. The string must be exactly one " + "character long." ); } @@ -421,14 +421,14 @@ public void Invoking(() => ValueConverter.ConvertValueToType(999)) .Should().Throw() .WithMessage( - $"Could not convert the value '999' ({typeof(Int32)}) to an enum member of the type " + + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); Invoking(() => ValueConverter.ConvertValueToType(999)) .Should().Throw() .WithMessage( - $"Could not convert the value '999' ({typeof(Int32)}) to an enum member of the type " + + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + $"{typeof(TestEnum?)}. That value does not match any of the values of the enum's members.*" ); } @@ -438,10 +438,10 @@ public void ConvertValueToTypeOfT_EnumTargetType_ShouldConvertToEnumMember() { var enumValue = Generate.Single(); - ValueConverter.ConvertValueToType((Int32)enumValue) + ValueConverter.ConvertValueToType((int)enumValue) .Should().Be(enumValue); - ValueConverter.ConvertValueToType((Int32)enumValue) + ValueConverter.ConvertValueToType((int)enumValue) .Should().Be(enumValue); } @@ -487,9 +487,9 @@ public void ConvertValueToTypeOfT_NonNullableTargetType_NullOrDBNullValue_Should public void ConvertValueToTypeOfT_NullableSourceType_ShouldConvertValueToTargetType( Type sourceType, Type targetType, - Boolean expectedCanConvert, - Object? sourceValue, - Object? expectedTargetValue + bool expectedCanConvert, + object? sourceValue, + object? expectedTargetValue ) { Assert.SkipUnless(sourceType.IsValueType, ""); @@ -509,16 +509,16 @@ public void ConvertValueToTypeOfT_NullableSourceType_ShouldConvertValueToTargetT [Fact] public void ConvertValueToTypeOfT_NullableTargetType_NullOrDBNullValue_ShouldReturnNull() { - ValueConverter.ConvertValueToType(DBNull.Value) + ValueConverter.ConvertValueToType(DBNull.Value) .Should().BeNull(); - ValueConverter.ConvertValueToType(DBNull.Value) + ValueConverter.ConvertValueToType(DBNull.Value) .Should().BeNull(); - ValueConverter.ConvertValueToType(null) + ValueConverter.ConvertValueToType(null) .Should().BeNull(); - ValueConverter.ConvertValueToType(null) + ValueConverter.ConvertValueToType(null) .Should().BeNull(); } @@ -527,9 +527,9 @@ public void ConvertValueToTypeOfT_NullableTargetType_NullOrDBNullValue_ShouldRet public void ConvertValueToTypeOfT_NullableTargetType_ShouldConvertValueToTargetType( Type sourceType, Type targetType, - Boolean expectedCanConvert, - Object? sourceValue, - Object? expectedTargetValue + bool expectedCanConvert, + object? sourceValue, + object? expectedTargetValue ) { Assert.SkipUnless(targetType.IsValueType, ""); @@ -551,9 +551,9 @@ public void ConvertValueToTypeOfT_NullableTargetType_ShouldConvertValueToTargetT public void ConvertValueToTypeOfT_ShouldConvertValueToType( Type _, Type targetType, - Boolean expectedCanConvert, - Object? sourceValue, - Object? expectedTargetValue + bool expectedCanConvert, + object? sourceValue, + object? expectedTargetValue ) { if (expectedCanConvert) @@ -561,7 +561,7 @@ public void ConvertValueToTypeOfT_ShouldConvertValueToType( var result = MaterializerFactoryHelper.MakeValueConverterConvertValueToTypeMethod(targetType) .Invoke(null, [sourceValue]); - if (result is Byte[] resultBytes && expectedTargetValue is Byte[] expectedTargetValueBytes) + if (result is byte[] resultBytes && expectedTargetValue is byte[] expectedTargetValueBytes) { resultBytes .Should().BeEquivalentTo( @@ -599,7 +599,7 @@ public void ConvertValueToTypeOfT_ValueCannotBeConvertedToTargetType_ShouldThrow Invoking(() => ValueConverter.ConvertValueToType("NotADate")) .Should().Throw() .WithMessage( - $"Could not convert the value 'NotADate' ({typeof(String)}) to the type {typeof(DateTime)}. See " + + $"Could not convert the value 'NotADate' ({typeof(string)}) to the type {typeof(DateTime)}. See " + "inner exception for details.*" ) .WithInnerException() @@ -608,8 +608,8 @@ public void ConvertValueToTypeOfT_ValueCannotBeConvertedToTargetType_ShouldThrow [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => ValueConverter.CanConvert(typeof(Int16), typeof(Int32))); - ArgumentNullGuardVerifier.Verify(() => ValueConverter.ConvertValueToType(1, typeof(Int32))); + ArgumentNullGuardVerifier.Verify(() => ValueConverter.CanConvert(typeof(short), typeof(int))); + ArgumentNullGuardVerifier.Verify(() => ValueConverter.ConvertValueToType(1, typeof(int))); } /// @@ -624,7 +624,7 @@ public void ShouldGuardAgainstNullArguments() /// /// The name of the culture to run the assertions under. /// The assertions to run. - private static void RunUnderCulture(String cultureName, Action assertions) + private static void RunUnderCulture(string cultureName, Action assertions) { var culture = new CultureInfo(cultureName); @@ -654,9 +654,9 @@ private static void RunUnderCulture(String cultureName, Action assertions) public static IEnumerable<( Type SourceType, Type TargetType, - Boolean ExpectedCanConvert, - Object SourceValue, - Object ExpectedTargetValue + bool ExpectedCanConvert, + object SourceValue, + object ExpectedTargetValue )> GetConvertTestData() { @@ -692,272 +692,272 @@ Object ExpectedTargetValue return new List<( Type SourceType, Type TargetType, - Boolean ExpectedCanConvert, - Object? SourceValue, - Object? ExpectedTargetValue + bool ExpectedCanConvert, + object? SourceValue, + object? ExpectedTargetValue )> { - (typeof(Boolean), typeof(Boolean), true, true, true), - (typeof(Boolean), typeof(Byte), true, true, (Byte)1), - (typeof(Boolean), typeof(Decimal), true, true, (Decimal)1), - (typeof(Boolean), typeof(Double), true, true, (Double)1), - (typeof(Boolean), typeof(Int16), true, true, (Int16)1), - (typeof(Boolean), typeof(Int32), true, true, 1), - (typeof(Boolean), typeof(Int64), true, true, (Int64)1), - (typeof(Boolean), typeof(Object), true, true, true), - (typeof(Boolean), typeof(SByte), true, true, (SByte)1), - (typeof(Boolean), typeof(Single), true, true, (Single)1), - (typeof(Boolean), typeof(String), true, true, "True"), - (typeof(Boolean), typeof(UInt16), true, true, (UInt16)1), - (typeof(Boolean), typeof(UInt32), true, true, (UInt32)1), - (typeof(Boolean), typeof(UInt64), true, true, (UInt64)1), - (typeof(Byte), typeof(Boolean), true, (Byte)1, true), - (typeof(Byte), typeof(Byte), true, byteValue, byteValue), - (typeof(Byte), typeof(Char), true, byteValue, (Char)byteValue), - (typeof(Byte), typeof(Decimal), true, byteValue, (Decimal)byteValue), - (typeof(Byte), typeof(Double), true, byteValue, (Double)byteValue), - (typeof(Byte), typeof(Int16), true, byteValue, (Int16)byteValue), - (typeof(Byte), typeof(Int32), true, byteValue, (Int32)byteValue), - (typeof(Byte), typeof(Int64), true, byteValue, (Int64)byteValue), - (typeof(Byte), typeof(Object), true, byteValue, byteValue), - (typeof(Byte), typeof(SByte), true, byteValue, (SByte)byteValue), - (typeof(Byte), typeof(Single), true, byteValue, (Single)byteValue), - (typeof(Byte), typeof(String), true, byteValue, byteValue.ToString(CultureInfo.InvariantCulture)), - (typeof(Byte), typeof(TestEnum), true, (Byte)enumValue, enumValue), - (typeof(Byte), typeof(UInt16), true, byteValue, (UInt16)byteValue), - (typeof(Byte), typeof(UInt32), true, byteValue, (UInt32)byteValue), - (typeof(Byte), typeof(UInt64), true, byteValue, (UInt64)byteValue), - (typeof(Byte[]), typeof(Guid), true, guidValue.ToByteArray(), guidValue), - (typeof(Char), typeof(Byte), true, charValue, (Byte)charValue), - (typeof(Char), typeof(Char), true, charValue, charValue), - (typeof(Char), typeof(Int16), true, charValue, (Int16)charValue), - (typeof(Char), typeof(Int32), true, charValue, (Int32)charValue), - (typeof(Char), typeof(Int64), true, charValue, (Int64)charValue), - (typeof(Char), typeof(Object), true, charValue, charValue), - (typeof(Char), typeof(SByte), true, charValue, (SByte)charValue), - (typeof(Char), typeof(String), true, charValue, charValue.ToString(CultureInfo.InvariantCulture)), - (typeof(Char), typeof(UInt16), true, charValue, (UInt16)charValue), - (typeof(Char), typeof(UInt32), true, charValue, (UInt32)charValue), - (typeof(Char), typeof(UInt64), true, charValue, (UInt64)charValue), + (typeof(bool), typeof(bool), true, true, true), + (typeof(bool), typeof(byte), true, true, (byte)1), + (typeof(bool), typeof(decimal), true, true, (decimal)1), + (typeof(bool), typeof(double), true, true, (double)1), + (typeof(bool), typeof(short), true, true, (short)1), + (typeof(bool), typeof(int), true, true, 1), + (typeof(bool), typeof(long), true, true, (long)1), + (typeof(bool), typeof(object), true, true, true), + (typeof(bool), typeof(sbyte), true, true, (sbyte)1), + (typeof(bool), typeof(float), true, true, (float)1), + (typeof(bool), typeof(string), true, true, "True"), + (typeof(bool), typeof(ushort), true, true, (ushort)1), + (typeof(bool), typeof(uint), true, true, (uint)1), + (typeof(bool), typeof(ulong), true, true, (ulong)1), + (typeof(byte), typeof(bool), true, (byte)1, true), + (typeof(byte), typeof(byte), true, byteValue, byteValue), + (typeof(byte), typeof(char), true, byteValue, (char)byteValue), + (typeof(byte), typeof(decimal), true, byteValue, (decimal)byteValue), + (typeof(byte), typeof(double), true, byteValue, (double)byteValue), + (typeof(byte), typeof(short), true, byteValue, (short)byteValue), + (typeof(byte), typeof(int), true, byteValue, (int)byteValue), + (typeof(byte), typeof(long), true, byteValue, (long)byteValue), + (typeof(byte), typeof(object), true, byteValue, byteValue), + (typeof(byte), typeof(sbyte), true, byteValue, (sbyte)byteValue), + (typeof(byte), typeof(float), true, byteValue, (float)byteValue), + (typeof(byte), typeof(string), true, byteValue, byteValue.ToString(CultureInfo.InvariantCulture)), + (typeof(byte), typeof(TestEnum), true, (byte)enumValue, enumValue), + (typeof(byte), typeof(ushort), true, byteValue, (ushort)byteValue), + (typeof(byte), typeof(uint), true, byteValue, (uint)byteValue), + (typeof(byte), typeof(ulong), true, byteValue, (ulong)byteValue), + (typeof(byte[]), typeof(Guid), true, guidValue.ToByteArray(), guidValue), + (typeof(char), typeof(byte), true, charValue, (byte)charValue), + (typeof(char), typeof(char), true, charValue, charValue), + (typeof(char), typeof(short), true, charValue, (short)charValue), + (typeof(char), typeof(int), true, charValue, (int)charValue), + (typeof(char), typeof(long), true, charValue, (long)charValue), + (typeof(char), typeof(object), true, charValue, charValue), + (typeof(char), typeof(sbyte), true, charValue, (sbyte)charValue), + (typeof(char), typeof(string), true, charValue, charValue.ToString(CultureInfo.InvariantCulture)), + (typeof(char), typeof(ushort), true, charValue, (ushort)charValue), + (typeof(char), typeof(uint), true, charValue, (uint)charValue), + (typeof(char), typeof(ulong), true, charValue, (ulong)charValue), (typeof(DateOnly), typeof(DateOnly), true, dateOnlyValue, dateOnlyValue), - (typeof(DateOnly), typeof(Object), true, dateOnlyValue, dateOnlyValue), - (typeof(DateOnly), typeof(String), true, dateOnlyValue, dateOnlyValue.ToString("O", CultureInfo.InvariantCulture)), + (typeof(DateOnly), typeof(object), true, dateOnlyValue, dateOnlyValue), + (typeof(DateOnly), typeof(string), true, dateOnlyValue, dateOnlyValue.ToString("O", CultureInfo.InvariantCulture)), (typeof(DateTime), typeof(DateOnly), true, dateOnlyValue.ToDateTime(TimeOnly.MinValue), dateOnlyValue), (typeof(DateTime), typeof(DateTime), true, dateTimeValue, dateTimeValue), - (typeof(DateTime), typeof(Object), true, dateTimeValue, dateTimeValue), - (typeof(DateTime), typeof(String), true, dateTimeValue, dateTimeValue.ToString("O", CultureInfo.InvariantCulture)), + (typeof(DateTime), typeof(object), true, dateTimeValue, dateTimeValue), + (typeof(DateTime), typeof(string), true, dateTimeValue, dateTimeValue.ToString("O", CultureInfo.InvariantCulture)), (typeof(DateTimeOffset), typeof(DateTimeOffset), true, dateTimeOffsetValue, dateTimeOffsetValue), - (typeof(DateTimeOffset), typeof(Object), true, dateTimeOffsetValue, dateTimeOffsetValue), - (typeof(DateTimeOffset), typeof(String), true, dateTimeOffsetValue, dateTimeOffsetValue.ToString("O", CultureInfo.InvariantCulture)), - (typeof(Decimal), typeof(Boolean), true, 1M, true), - (typeof(Decimal), typeof(Byte), true, decimalValue, Convert.ChangeType(decimalValue, typeof(Byte), CultureInfo.InvariantCulture)), - (typeof(Decimal), typeof(Decimal), true, decimalValue, decimalValue), - (typeof(Decimal), typeof(Double), true, decimalValue, Convert.ChangeType(decimalValue, typeof(Double), CultureInfo.InvariantCulture)), - (typeof(Decimal), typeof(Int16), true, decimalValue, Convert.ChangeType(decimalValue, typeof(Int16), CultureInfo.InvariantCulture)), - (typeof(Decimal), typeof(Int32), true, decimalValue, Convert.ChangeType(decimalValue, typeof(Int32), CultureInfo.InvariantCulture)), - (typeof(Decimal), typeof(Int64), true, decimalValue, Convert.ChangeType(decimalValue, typeof(Int64), CultureInfo.InvariantCulture)), - (typeof(Decimal), typeof(Object), true, decimalValue, decimalValue), - (typeof(Decimal), typeof(SByte), true, decimalValue, Convert.ChangeType(decimalValue, typeof(SByte), CultureInfo.InvariantCulture)), - (typeof(Decimal), typeof(Single), true, decimalValue, Convert.ChangeType(decimalValue, typeof(Single), CultureInfo.InvariantCulture)), - (typeof(Decimal), typeof(String), true, decimalValue, decimalValue.ToString(CultureInfo.InvariantCulture)), - (typeof(Decimal), typeof(TestEnum), true, (Decimal)enumValue, enumValue), - (typeof(Decimal), typeof(UInt16), true, decimalValue, Convert.ChangeType(decimalValue, typeof(UInt16), CultureInfo.InvariantCulture)), - (typeof(Decimal), typeof(UInt32), true, decimalValue, Convert.ChangeType(decimalValue, typeof(UInt32), CultureInfo.InvariantCulture)), - (typeof(Decimal), typeof(UInt64), true, decimalValue, Convert.ChangeType(decimalValue, typeof(UInt64), CultureInfo.InvariantCulture)), - (typeof(Double), typeof(Boolean), true, 1.0, true), - (typeof(Double), typeof(Byte), true, doubleValue, Convert.ChangeType(doubleValue, typeof(Byte), CultureInfo.InvariantCulture)), - (typeof(Double), typeof(Decimal), true, doubleValue, Convert.ChangeType(doubleValue, typeof(Decimal), CultureInfo.InvariantCulture)), - (typeof(Double), typeof(Double), true, doubleValue, doubleValue), - (typeof(Double), typeof(Int16), true, doubleValue, Convert.ChangeType(doubleValue, typeof(Int16), CultureInfo.InvariantCulture)), - (typeof(Double), typeof(Int32), true, doubleValue, Convert.ChangeType(doubleValue, typeof(Int32), CultureInfo.InvariantCulture)), - (typeof(Double), typeof(Int64), true, doubleValue, Convert.ChangeType(doubleValue, typeof(Int64), CultureInfo.InvariantCulture)), - (typeof(Double), typeof(Object), true, doubleValue, doubleValue), - (typeof(Double), typeof(SByte), true, doubleValue, Convert.ChangeType(doubleValue, typeof(SByte), CultureInfo.InvariantCulture)), - (typeof(Double), typeof(Single), true, doubleValue, Convert.ChangeType(doubleValue, typeof(Single), CultureInfo.InvariantCulture)), - (typeof(Double), typeof(String), true, doubleValue, doubleValue.ToString(CultureInfo.InvariantCulture)), - (typeof(Double), typeof(TestEnum), true, (Double)enumValue, enumValue), - (typeof(Double), typeof(UInt16), true, doubleValue, Convert.ChangeType(doubleValue, typeof(UInt16), CultureInfo.InvariantCulture)), - (typeof(Double), typeof(UInt32), true, doubleValue, Convert.ChangeType(doubleValue, typeof(UInt32), CultureInfo.InvariantCulture)), - (typeof(Double), typeof(UInt64), true, doubleValue, Convert.ChangeType(doubleValue, typeof(UInt64), CultureInfo.InvariantCulture)), - (typeof(Guid), typeof(Byte[]), true, guidValue, guidValue.ToByteArray()), + (typeof(DateTimeOffset), typeof(object), true, dateTimeOffsetValue, dateTimeOffsetValue), + (typeof(DateTimeOffset), typeof(string), true, dateTimeOffsetValue, dateTimeOffsetValue.ToString("O", CultureInfo.InvariantCulture)), + (typeof(decimal), typeof(bool), true, 1M, true), + (typeof(decimal), typeof(byte), true, decimalValue, Convert.ChangeType(decimalValue, typeof(byte), CultureInfo.InvariantCulture)), + (typeof(decimal), typeof(decimal), true, decimalValue, decimalValue), + (typeof(decimal), typeof(double), true, decimalValue, Convert.ChangeType(decimalValue, typeof(double), CultureInfo.InvariantCulture)), + (typeof(decimal), typeof(short), true, decimalValue, Convert.ChangeType(decimalValue, typeof(short), CultureInfo.InvariantCulture)), + (typeof(decimal), typeof(int), true, decimalValue, Convert.ChangeType(decimalValue, typeof(int), CultureInfo.InvariantCulture)), + (typeof(decimal), typeof(long), true, decimalValue, Convert.ChangeType(decimalValue, typeof(long), CultureInfo.InvariantCulture)), + (typeof(decimal), typeof(object), true, decimalValue, decimalValue), + (typeof(decimal), typeof(sbyte), true, decimalValue, Convert.ChangeType(decimalValue, typeof(sbyte), CultureInfo.InvariantCulture)), + (typeof(decimal), typeof(float), true, decimalValue, Convert.ChangeType(decimalValue, typeof(float), CultureInfo.InvariantCulture)), + (typeof(decimal), typeof(string), true, decimalValue, decimalValue.ToString(CultureInfo.InvariantCulture)), + (typeof(decimal), typeof(TestEnum), true, (decimal)enumValue, enumValue), + (typeof(decimal), typeof(ushort), true, decimalValue, Convert.ChangeType(decimalValue, typeof(ushort), CultureInfo.InvariantCulture)), + (typeof(decimal), typeof(uint), true, decimalValue, Convert.ChangeType(decimalValue, typeof(uint), CultureInfo.InvariantCulture)), + (typeof(decimal), typeof(ulong), true, decimalValue, Convert.ChangeType(decimalValue, typeof(ulong), CultureInfo.InvariantCulture)), + (typeof(double), typeof(bool), true, 1.0, true), + (typeof(double), typeof(byte), true, doubleValue, Convert.ChangeType(doubleValue, typeof(byte), CultureInfo.InvariantCulture)), + (typeof(double), typeof(decimal), true, doubleValue, Convert.ChangeType(doubleValue, typeof(decimal), CultureInfo.InvariantCulture)), + (typeof(double), typeof(double), true, doubleValue, doubleValue), + (typeof(double), typeof(short), true, doubleValue, Convert.ChangeType(doubleValue, typeof(short), CultureInfo.InvariantCulture)), + (typeof(double), typeof(int), true, doubleValue, Convert.ChangeType(doubleValue, typeof(int), CultureInfo.InvariantCulture)), + (typeof(double), typeof(long), true, doubleValue, Convert.ChangeType(doubleValue, typeof(long), CultureInfo.InvariantCulture)), + (typeof(double), typeof(object), true, doubleValue, doubleValue), + (typeof(double), typeof(sbyte), true, doubleValue, Convert.ChangeType(doubleValue, typeof(sbyte), CultureInfo.InvariantCulture)), + (typeof(double), typeof(float), true, doubleValue, Convert.ChangeType(doubleValue, typeof(float), CultureInfo.InvariantCulture)), + (typeof(double), typeof(string), true, doubleValue, doubleValue.ToString(CultureInfo.InvariantCulture)), + (typeof(double), typeof(TestEnum), true, (double)enumValue, enumValue), + (typeof(double), typeof(ushort), true, doubleValue, Convert.ChangeType(doubleValue, typeof(ushort), CultureInfo.InvariantCulture)), + (typeof(double), typeof(uint), true, doubleValue, Convert.ChangeType(doubleValue, typeof(uint), CultureInfo.InvariantCulture)), + (typeof(double), typeof(ulong), true, doubleValue, Convert.ChangeType(doubleValue, typeof(ulong), CultureInfo.InvariantCulture)), + (typeof(Guid), typeof(byte[]), true, guidValue, guidValue.ToByteArray()), (typeof(Guid), typeof(Guid), true, guidValue, guidValue), - (typeof(Guid), typeof(Object), true, guidValue, guidValue), - (typeof(Guid), typeof(String), true, guidValue, guidValue.ToString("D")), - (typeof(Int16), typeof(Boolean), true, (Int16)1, true), - (typeof(Int16), typeof(Byte), true, int16Value, (Byte) int16Value), - (typeof(Int16), typeof(Char), true, int16Value, (Char) int16Value), - (typeof(Int16), typeof(Decimal), true, int16Value, (Decimal) int16Value), - (typeof(Int16), typeof(Double), true, int16Value, (Double)int16Value), - (typeof(Int16), typeof(Int16), true, int16Value, int16Value), - (typeof(Int16), typeof(Int32), true, int16Value, (Int32)int16Value), - (typeof(Int16), typeof(Int64), true, int16Value, (Int64)int16Value), - (typeof(Int16), typeof(Object), true, int16Value, int16Value), - (typeof(Int16), typeof(SByte), true, int16Value, (SByte)int16Value), - (typeof(Int16), typeof(Single), true, int16Value, (Single)int16Value), - (typeof(Int16), typeof(String), true, int16Value, int16Value.ToString(CultureInfo.InvariantCulture)), - (typeof(Int16), typeof(TestEnum), true, (Int16)enumValue, enumValue), - (typeof(Int16), typeof(UInt16), true, int16Value, (UInt16)int16Value), - (typeof(Int16), typeof(UInt32), true, int16Value, (UInt32)int16Value), - (typeof(Int16), typeof(UInt64), true, int16Value, (UInt64)int16Value), - (typeof(Int32), typeof(Boolean), true, 1, true), - (typeof(Int32), typeof(Byte), true, int32Value, (Byte)int32Value), - (typeof(Int32), typeof(Char), true, int32Value, (Char) int32Value), - (typeof(Int32), typeof(Decimal), true, int32Value, (Decimal)int32Value), - (typeof(Int32), typeof(Double), true, int32Value, (Double)int32Value), - (typeof(Int32), typeof(Int16), true, int32Value, (Int16)int32Value), - (typeof(Int32), typeof(Int32), true, int32Value, int32Value), - (typeof(Int32), typeof(Int64), true, int32Value, (Int64)int32Value), - (typeof(Int32), typeof(Object), true, int32Value, int32Value), - (typeof(Int32), typeof(SByte), true, int32Value, (SByte)int32Value), - (typeof(Int32), typeof(Single), true, int32Value, (Single)int32Value), - (typeof(Int32), typeof(String), true, int32Value, int32Value.ToString(CultureInfo.InvariantCulture)), - (typeof(Int32), typeof(TestEnum), true, (Int32)enumValue, enumValue), - (typeof(Int32), typeof(UInt16), true, int32Value, (UInt16)int32Value), - (typeof(Int32), typeof(UInt32), true, int32Value, (UInt32)int32Value), - (typeof(Int32), typeof(UInt64), true, int32Value, (UInt64)int32Value), - (typeof(Int64), typeof(Boolean), true, (Int64)1, true), - (typeof(Int64), typeof(Byte), true, int64Value, (Byte) int64Value), - (typeof(Int64), typeof(Char), true, int64Value, (Char) int64Value), - (typeof(Int64), typeof(Decimal), true, int64Value, (Decimal) int64Value), - (typeof(Int64), typeof(Double), true, int64Value, (Double)int64Value), - (typeof(Int64), typeof(Int16), true, int64Value, (Int16)int64Value), - (typeof(Int64), typeof(Int32), true, int64Value, (Int32)int64Value), - (typeof(Int64), typeof(Int64), true, int64Value, int64Value), - (typeof(Int64), typeof(Object), true, int64Value, int64Value), - (typeof(Int64), typeof(SByte), true, int64Value, (SByte)int64Value), - (typeof(Int64), typeof(Single), true, int64Value, (Single)int64Value), - (typeof(Int64), typeof(String), true, int64Value, int64Value.ToString(CultureInfo.InvariantCulture)), - (typeof(Int64), typeof(TestEnum), true, (Int64)enumValue, enumValue), - (typeof(Int64), typeof(UInt16), true, int64Value, (UInt16)int64Value), - (typeof(Int64), typeof(UInt32), true, int64Value, (UInt32)int64Value), - (typeof(Int64), typeof(UInt64), true, int64Value, (UInt64)int64Value), + (typeof(Guid), typeof(object), true, guidValue, guidValue), + (typeof(Guid), typeof(string), true, guidValue, guidValue.ToString("D")), + (typeof(short), typeof(bool), true, (short)1, true), + (typeof(short), typeof(byte), true, int16Value, (byte) int16Value), + (typeof(short), typeof(char), true, int16Value, (char) int16Value), + (typeof(short), typeof(decimal), true, int16Value, (decimal) int16Value), + (typeof(short), typeof(double), true, int16Value, (double)int16Value), + (typeof(short), typeof(short), true, int16Value, int16Value), + (typeof(short), typeof(int), true, int16Value, (int)int16Value), + (typeof(short), typeof(long), true, int16Value, (long)int16Value), + (typeof(short), typeof(object), true, int16Value, int16Value), + (typeof(short), typeof(sbyte), true, int16Value, (sbyte)int16Value), + (typeof(short), typeof(float), true, int16Value, (float)int16Value), + (typeof(short), typeof(string), true, int16Value, int16Value.ToString(CultureInfo.InvariantCulture)), + (typeof(short), typeof(TestEnum), true, (short)enumValue, enumValue), + (typeof(short), typeof(ushort), true, int16Value, (ushort)int16Value), + (typeof(short), typeof(uint), true, int16Value, (uint)int16Value), + (typeof(short), typeof(ulong), true, int16Value, (ulong)int16Value), + (typeof(int), typeof(bool), true, 1, true), + (typeof(int), typeof(byte), true, int32Value, (byte)int32Value), + (typeof(int), typeof(char), true, int32Value, (char) int32Value), + (typeof(int), typeof(decimal), true, int32Value, (decimal)int32Value), + (typeof(int), typeof(double), true, int32Value, (double)int32Value), + (typeof(int), typeof(short), true, int32Value, (short)int32Value), + (typeof(int), typeof(int), true, int32Value, int32Value), + (typeof(int), typeof(long), true, int32Value, (long)int32Value), + (typeof(int), typeof(object), true, int32Value, int32Value), + (typeof(int), typeof(sbyte), true, int32Value, (sbyte)int32Value), + (typeof(int), typeof(float), true, int32Value, (float)int32Value), + (typeof(int), typeof(string), true, int32Value, int32Value.ToString(CultureInfo.InvariantCulture)), + (typeof(int), typeof(TestEnum), true, (int)enumValue, enumValue), + (typeof(int), typeof(ushort), true, int32Value, (ushort)int32Value), + (typeof(int), typeof(uint), true, int32Value, (uint)int32Value), + (typeof(int), typeof(ulong), true, int32Value, (ulong)int32Value), + (typeof(long), typeof(bool), true, (long)1, true), + (typeof(long), typeof(byte), true, int64Value, (byte) int64Value), + (typeof(long), typeof(char), true, int64Value, (char) int64Value), + (typeof(long), typeof(decimal), true, int64Value, (decimal) int64Value), + (typeof(long), typeof(double), true, int64Value, (double)int64Value), + (typeof(long), typeof(short), true, int64Value, (short)int64Value), + (typeof(long), typeof(int), true, int64Value, (int)int64Value), + (typeof(long), typeof(long), true, int64Value, int64Value), + (typeof(long), typeof(object), true, int64Value, int64Value), + (typeof(long), typeof(sbyte), true, int64Value, (sbyte)int64Value), + (typeof(long), typeof(float), true, int64Value, (float)int64Value), + (typeof(long), typeof(string), true, int64Value, int64Value.ToString(CultureInfo.InvariantCulture)), + (typeof(long), typeof(TestEnum), true, (long)enumValue, enumValue), + (typeof(long), typeof(ushort), true, int64Value, (ushort)int64Value), + (typeof(long), typeof(uint), true, int64Value, (uint)int64Value), + (typeof(long), typeof(ulong), true, int64Value, (ulong)int64Value), (typeof(IntPtr), typeof(IntPtr), true, intPtrValue, intPtrValue), - (typeof(IntPtr), typeof(Object), true, intPtrValue, intPtrValue), - (typeof(SByte), typeof(Boolean), true, (SByte)1, true), - (typeof(SByte), typeof(Byte), true, sbyteValue, (Byte)sbyteValue), - (typeof(SByte), typeof(Char), true, sbyteValue, (Char) sbyteValue), - (typeof(SByte), typeof(Decimal), true, sbyteValue, (Decimal)sbyteValue), - (typeof(SByte), typeof(Double), true, sbyteValue, (Double)sbyteValue), - (typeof(SByte), typeof(Int16), true, sbyteValue, (Int16)sbyteValue), - (typeof(SByte), typeof(Int32), true, sbyteValue, (Int32)sbyteValue), - (typeof(SByte), typeof(Int64), true, sbyteValue, (Int64)sbyteValue), - (typeof(SByte), typeof(Object), true, sbyteValue, sbyteValue), - (typeof(SByte), typeof(SByte), true, sbyteValue, sbyteValue), - (typeof(SByte), typeof(Single), true, sbyteValue, (Single)sbyteValue), - (typeof(SByte), typeof(String), true, sbyteValue, sbyteValue.ToString(CultureInfo.InvariantCulture)), - (typeof(SByte), typeof(TestEnum), true, (SByte)enumValue, enumValue), - (typeof(SByte), typeof(UInt16), true, sbyteValue, (UInt16)sbyteValue), - (typeof(SByte), typeof(UInt32), true, sbyteValue, (UInt32)sbyteValue), - (typeof(SByte), typeof(UInt64), true, sbyteValue, (UInt64)sbyteValue), - (typeof(Single), typeof(Boolean), true, (Single)1, true), - (typeof(Single), typeof(Byte), true, singleValue, Convert.ChangeType(singleValue, typeof(Byte), CultureInfo.InvariantCulture)), - (typeof(Single), typeof(Decimal), true, singleValue, Convert.ChangeType(singleValue, typeof(Decimal), CultureInfo.InvariantCulture)), - (typeof(Single), typeof(Double), true, singleValue, Convert.ChangeType(singleValue, typeof(Double), CultureInfo.InvariantCulture)), - (typeof(Single), typeof(Int16), true, singleValue, Convert.ChangeType(singleValue, typeof(Int16), CultureInfo.InvariantCulture)), - (typeof(Single), typeof(Int32), true, singleValue, Convert.ChangeType(singleValue, typeof(Int32), CultureInfo.InvariantCulture)), - (typeof(Single), typeof(Int64), true, singleValue, Convert.ChangeType(singleValue, typeof(Int64), CultureInfo.InvariantCulture)), - (typeof(Single), typeof(Object), true, singleValue, singleValue), - (typeof(Single), typeof(SByte), true, singleValue, Convert.ChangeType(singleValue, typeof(SByte), CultureInfo.InvariantCulture)), - (typeof(Single), typeof(Single), true, singleValue, Convert.ChangeType(singleValue, typeof(Single), CultureInfo.InvariantCulture)), - (typeof(Single), typeof(String), true, singleValue, singleValue.ToString(CultureInfo.InvariantCulture)), - (typeof(Single), typeof(TestEnum), true, (Single)enumValue, enumValue), - (typeof(Single), typeof(UInt16), true, singleValue, Convert.ChangeType(singleValue, typeof(UInt16), CultureInfo.InvariantCulture)), - (typeof(Single), typeof(UInt32), true, singleValue, Convert.ChangeType(singleValue, typeof(UInt32), CultureInfo.InvariantCulture)), - (typeof(Single), typeof(UInt64), true, singleValue, Convert.ChangeType(singleValue, typeof(UInt64), CultureInfo.InvariantCulture)), - (typeof(String), typeof(Boolean), true, "True", true), - (typeof(String), typeof(Byte), true, byteValue.ToString(CultureInfo.InvariantCulture), byteValue), - (typeof(String), typeof(Char), true, charValue.ToString(CultureInfo.InvariantCulture), charValue), - (typeof(String), typeof(DateOnly), true, dateOnlyValue.ToString("O", CultureInfo.InvariantCulture), dateOnlyValue), - (typeof(String), typeof(DateTime), true, dateTimeValue.ToString("O", CultureInfo.InvariantCulture), dateTimeValue), - (typeof(String), typeof(DateTimeOffset), true, dateTimeOffsetValue.ToString("O", CultureInfo.InvariantCulture), dateTimeOffsetValue), - (typeof(String), typeof(Decimal), true, decimalValue.ToString(CultureInfo.InvariantCulture), decimalValue), - (typeof(String), typeof(Double), true, doubleValue.ToString(CultureInfo.InvariantCulture), doubleValue), - (typeof(String), typeof(Guid), true, guidValue.ToString("D"), guidValue), - (typeof(String), typeof(Int16), true, int16Value.ToString(CultureInfo.InvariantCulture), int16Value), - (typeof(String), typeof(Int32), true, int32Value.ToString(CultureInfo.InvariantCulture), int32Value), - (typeof(String), typeof(Int64), true, int64Value.ToString(CultureInfo.InvariantCulture), int64Value), - (typeof(String), typeof(Object), true, stringValue, stringValue), - (typeof(String), typeof(SByte), true, sbyteValue.ToString(CultureInfo.InvariantCulture), sbyteValue), - (typeof(String), typeof(Single), true, singleValue.ToString(CultureInfo.InvariantCulture), singleValue), - (typeof(String), typeof(String), true, stringValue, stringValue), - (typeof(String), typeof(TestEnum), true, enumValue.ToString(), enumValue), - (typeof(String), typeof(TimeSpan), true, timeSpanValue.ToString("g", CultureInfo.InvariantCulture), timeSpanValue), - (typeof(String), typeof(UInt16), true, uint16Value.ToString(CultureInfo.InvariantCulture), uint16Value), - (typeof(String), typeof(UInt32), true, uint32Value.ToString(CultureInfo.InvariantCulture), uint32Value), - (typeof(String), typeof(UInt64), true, uint64Value.ToString(CultureInfo.InvariantCulture), uint64Value), - (typeof(TestEnum), typeof(Byte), true, enumValue, (Byte)enumValue), - (typeof(TestEnum), typeof(Decimal), true, enumValue, (Decimal)enumValue), - (typeof(TestEnum), typeof(Double), true, enumValue, (Double)enumValue), - (typeof(TestEnum), typeof(Int16), true, enumValue, (Int16)enumValue), - (typeof(TestEnum), typeof(Int32), true, enumValue, (Int32)enumValue), - (typeof(TestEnum), typeof(Int64), true, enumValue, (Int64)enumValue), - (typeof(TestEnum), typeof(Object), true, enumValue, enumValue), - (typeof(TestEnum), typeof(SByte), true, enumValue, (SByte)enumValue), - (typeof(TestEnum), typeof(Single), true, enumValue, (Single)enumValue), - (typeof(TestEnum), typeof(String), true, enumValue, enumValue.ToString()), + (typeof(IntPtr), typeof(object), true, intPtrValue, intPtrValue), + (typeof(sbyte), typeof(bool), true, (sbyte)1, true), + (typeof(sbyte), typeof(byte), true, sbyteValue, (byte)sbyteValue), + (typeof(sbyte), typeof(char), true, sbyteValue, (char) sbyteValue), + (typeof(sbyte), typeof(decimal), true, sbyteValue, (decimal)sbyteValue), + (typeof(sbyte), typeof(double), true, sbyteValue, (double)sbyteValue), + (typeof(sbyte), typeof(short), true, sbyteValue, (short)sbyteValue), + (typeof(sbyte), typeof(int), true, sbyteValue, (int)sbyteValue), + (typeof(sbyte), typeof(long), true, sbyteValue, (long)sbyteValue), + (typeof(sbyte), typeof(object), true, sbyteValue, sbyteValue), + (typeof(sbyte), typeof(sbyte), true, sbyteValue, sbyteValue), + (typeof(sbyte), typeof(float), true, sbyteValue, (float)sbyteValue), + (typeof(sbyte), typeof(string), true, sbyteValue, sbyteValue.ToString(CultureInfo.InvariantCulture)), + (typeof(sbyte), typeof(TestEnum), true, (sbyte)enumValue, enumValue), + (typeof(sbyte), typeof(ushort), true, sbyteValue, (ushort)sbyteValue), + (typeof(sbyte), typeof(uint), true, sbyteValue, (uint)sbyteValue), + (typeof(sbyte), typeof(ulong), true, sbyteValue, (ulong)sbyteValue), + (typeof(float), typeof(bool), true, (float)1, true), + (typeof(float), typeof(byte), true, singleValue, Convert.ChangeType(singleValue, typeof(byte), CultureInfo.InvariantCulture)), + (typeof(float), typeof(decimal), true, singleValue, Convert.ChangeType(singleValue, typeof(decimal), CultureInfo.InvariantCulture)), + (typeof(float), typeof(double), true, singleValue, Convert.ChangeType(singleValue, typeof(double), CultureInfo.InvariantCulture)), + (typeof(float), typeof(short), true, singleValue, Convert.ChangeType(singleValue, typeof(short), CultureInfo.InvariantCulture)), + (typeof(float), typeof(int), true, singleValue, Convert.ChangeType(singleValue, typeof(int), CultureInfo.InvariantCulture)), + (typeof(float), typeof(long), true, singleValue, Convert.ChangeType(singleValue, typeof(long), CultureInfo.InvariantCulture)), + (typeof(float), typeof(object), true, singleValue, singleValue), + (typeof(float), typeof(sbyte), true, singleValue, Convert.ChangeType(singleValue, typeof(sbyte), CultureInfo.InvariantCulture)), + (typeof(float), typeof(float), true, singleValue, Convert.ChangeType(singleValue, typeof(float), CultureInfo.InvariantCulture)), + (typeof(float), typeof(string), true, singleValue, singleValue.ToString(CultureInfo.InvariantCulture)), + (typeof(float), typeof(TestEnum), true, (float)enumValue, enumValue), + (typeof(float), typeof(ushort), true, singleValue, Convert.ChangeType(singleValue, typeof(ushort), CultureInfo.InvariantCulture)), + (typeof(float), typeof(uint), true, singleValue, Convert.ChangeType(singleValue, typeof(uint), CultureInfo.InvariantCulture)), + (typeof(float), typeof(ulong), true, singleValue, Convert.ChangeType(singleValue, typeof(ulong), CultureInfo.InvariantCulture)), + (typeof(string), typeof(bool), true, "True", true), + (typeof(string), typeof(byte), true, byteValue.ToString(CultureInfo.InvariantCulture), byteValue), + (typeof(string), typeof(char), true, charValue.ToString(CultureInfo.InvariantCulture), charValue), + (typeof(string), typeof(DateOnly), true, dateOnlyValue.ToString("O", CultureInfo.InvariantCulture), dateOnlyValue), + (typeof(string), typeof(DateTime), true, dateTimeValue.ToString("O", CultureInfo.InvariantCulture), dateTimeValue), + (typeof(string), typeof(DateTimeOffset), true, dateTimeOffsetValue.ToString("O", CultureInfo.InvariantCulture), dateTimeOffsetValue), + (typeof(string), typeof(decimal), true, decimalValue.ToString(CultureInfo.InvariantCulture), decimalValue), + (typeof(string), typeof(double), true, doubleValue.ToString(CultureInfo.InvariantCulture), doubleValue), + (typeof(string), typeof(Guid), true, guidValue.ToString("D"), guidValue), + (typeof(string), typeof(short), true, int16Value.ToString(CultureInfo.InvariantCulture), int16Value), + (typeof(string), typeof(int), true, int32Value.ToString(CultureInfo.InvariantCulture), int32Value), + (typeof(string), typeof(long), true, int64Value.ToString(CultureInfo.InvariantCulture), int64Value), + (typeof(string), typeof(object), true, stringValue, stringValue), + (typeof(string), typeof(sbyte), true, sbyteValue.ToString(CultureInfo.InvariantCulture), sbyteValue), + (typeof(string), typeof(float), true, singleValue.ToString(CultureInfo.InvariantCulture), singleValue), + (typeof(string), typeof(string), true, stringValue, stringValue), + (typeof(string), typeof(TestEnum), true, enumValue.ToString(), enumValue), + (typeof(string), typeof(TimeSpan), true, timeSpanValue.ToString("g", CultureInfo.InvariantCulture), timeSpanValue), + (typeof(string), typeof(ushort), true, uint16Value.ToString(CultureInfo.InvariantCulture), uint16Value), + (typeof(string), typeof(uint), true, uint32Value.ToString(CultureInfo.InvariantCulture), uint32Value), + (typeof(string), typeof(ulong), true, uint64Value.ToString(CultureInfo.InvariantCulture), uint64Value), + (typeof(TestEnum), typeof(byte), true, enumValue, (byte)enumValue), + (typeof(TestEnum), typeof(decimal), true, enumValue, (decimal)enumValue), + (typeof(TestEnum), typeof(double), true, enumValue, (double)enumValue), + (typeof(TestEnum), typeof(short), true, enumValue, (short)enumValue), + (typeof(TestEnum), typeof(int), true, enumValue, (int)enumValue), + (typeof(TestEnum), typeof(long), true, enumValue, (long)enumValue), + (typeof(TestEnum), typeof(object), true, enumValue, enumValue), + (typeof(TestEnum), typeof(sbyte), true, enumValue, (sbyte)enumValue), + (typeof(TestEnum), typeof(float), true, enumValue, (float)enumValue), + (typeof(TestEnum), typeof(string), true, enumValue, enumValue.ToString()), (typeof(TestEnum), typeof(TestEnum), true, enumValue, enumValue), - (typeof(TestEnum), typeof(UInt16), true, enumValue, (UInt16)enumValue), - (typeof(TestEnum), typeof(UInt32), true, enumValue, (UInt32)enumValue), - (typeof(TestEnum), typeof(UInt64), true, enumValue, (UInt64)enumValue), - (typeof(TimeOnly), typeof(Object), true, timeOnlyValue, timeOnlyValue), - (typeof(TimeOnly), typeof(String), true, timeOnlyValue, timeOnlyValue.ToString("O", CultureInfo.InvariantCulture)), + (typeof(TestEnum), typeof(ushort), true, enumValue, (ushort)enumValue), + (typeof(TestEnum), typeof(uint), true, enumValue, (uint)enumValue), + (typeof(TestEnum), typeof(ulong), true, enumValue, (ulong)enumValue), + (typeof(TimeOnly), typeof(object), true, timeOnlyValue, timeOnlyValue), + (typeof(TimeOnly), typeof(string), true, timeOnlyValue, timeOnlyValue.ToString("O", CultureInfo.InvariantCulture)), (typeof(TimeOnly), typeof(TimeOnly), true, timeOnlyValue, timeOnlyValue), - (typeof(TimeSpan), typeof(Object), true, timeSpanValue, timeSpanValue), - (typeof(TimeSpan), typeof(String), true, timeSpanValue, timeSpanValue.ToString("g", CultureInfo.InvariantCulture)), + (typeof(TimeSpan), typeof(object), true, timeSpanValue, timeSpanValue), + (typeof(TimeSpan), typeof(string), true, timeSpanValue, timeSpanValue.ToString("g", CultureInfo.InvariantCulture)), (typeof(TimeSpan), typeof(TimeOnly), true, timeSpanValue, TimeOnly.FromTimeSpan(timeSpanValue)), (typeof(TimeSpan), typeof(TimeSpan), true, timeSpanValue, timeSpanValue), - (typeof(UInt16), typeof(Boolean), true, (UInt16)1, true), - (typeof(UInt16), typeof(Byte), true, uint16Value, (Byte) uint16Value), - (typeof(UInt16), typeof(Char), true, uint16Value, (Char) uint16Value), - (typeof(UInt16), typeof(Decimal), true, uint16Value, (Decimal) uint16Value), - (typeof(UInt16), typeof(Double), true, uint16Value, (Double)uint16Value), - (typeof(UInt16), typeof(Int16), true, uint16Value, (Int16)uint16Value), - (typeof(UInt16), typeof(Int32), true, uint16Value, (Int32)uint16Value), - (typeof(UInt16), typeof(Int64), true, uint16Value, (Int64)uint16Value), - (typeof(UInt16), typeof(Object), true, uint16Value, uint16Value), - (typeof(UInt16), typeof(SByte), true, uint16Value, (SByte)uint16Value), - (typeof(UInt16), typeof(Single), true, uint16Value, (Single)uint16Value), - (typeof(UInt16), typeof(String), true, uint16Value, uint16Value.ToString(CultureInfo.InvariantCulture)), - (typeof(UInt16), typeof(TestEnum), true, (UInt16)enumValue, enumValue), - (typeof(UInt16), typeof(UInt16), true, uint16Value, uint16Value), - (typeof(UInt16), typeof(UInt32), true, uint16Value, (UInt32)uint16Value), - (typeof(UInt16), typeof(UInt64), true, uint16Value, (UInt64)uint16Value), - (typeof(UInt32), typeof(Boolean), true, (UInt32)1, true), - (typeof(UInt32), typeof(Byte), true, uint32Value, (Byte) uint32Value), - (typeof(UInt32), typeof(Char), true, uint32Value, (Char) uint32Value), - (typeof(UInt32), typeof(Decimal), true, uint32Value, (Decimal) uint32Value), - (typeof(UInt32), typeof(Double), true, uint32Value, (Double)uint32Value), - (typeof(UInt32), typeof(Int32), true, uint32Value, (Int32)uint32Value), - (typeof(UInt32), typeof(Int32), true, uint32Value, (Int32)uint32Value), - (typeof(UInt32), typeof(Int64), true, uint32Value, (Int64)uint32Value), - (typeof(UInt32), typeof(Object), true, uint32Value, uint32Value), - (typeof(UInt32), typeof(SByte), true, uint32Value, (SByte)uint32Value), - (typeof(UInt32), typeof(Single), true, uint32Value, (Single)uint32Value), - (typeof(UInt32), typeof(String), true, uint32Value, uint32Value.ToString(CultureInfo.InvariantCulture)), - (typeof(UInt32), typeof(TestEnum), true, (UInt32)enumValue, enumValue), - (typeof(UInt32), typeof(UInt16), true, uint32Value, (UInt16)uint32Value), - (typeof(UInt32), typeof(UInt32), true, uint32Value, uint32Value), - (typeof(UInt32), typeof(UInt64), true, uint32Value, (UInt64)uint32Value), - (typeof(UInt64), typeof(Boolean), true, (UInt64)1, true), - (typeof(UInt64), typeof(Byte), true, uint64Value, (Byte) uint64Value), - (typeof(UInt64), typeof(Char), true, uint64Value, (Char) uint64Value), - (typeof(UInt64), typeof(Decimal), true, uint64Value, (Decimal) uint64Value), - (typeof(UInt64), typeof(Double), true, uint64Value, (Double)uint64Value), - (typeof(UInt64), typeof(Int16), true, uint64Value, (Int16)uint64Value), - (typeof(UInt64), typeof(Int32), true, uint64Value, (Int32)uint64Value), - (typeof(UInt64), typeof(Int64), true, uint64Value, (Int64)uint64Value), - (typeof(UInt64), typeof(Object), true, uint64Value, uint64Value), - (typeof(UInt64), typeof(SByte), true, uint64Value, (SByte)uint64Value), - (typeof(UInt64), typeof(Single), true, uint64Value, (Single)uint64Value), - (typeof(UInt64), typeof(String), true, uint64Value, uint64Value.ToString(CultureInfo.InvariantCulture)), - (typeof(UInt64), typeof(TestEnum), true, (UInt64)enumValue, enumValue), - (typeof(UInt64), typeof(UInt16), true, uint64Value, (UInt16)uint64Value), - (typeof(UInt64), typeof(UInt32), true, uint64Value, (UInt32)uint64Value), - (typeof(UInt64), typeof(UInt64), true, uint64Value, uint64Value), - (typeof(UIntPtr), typeof(Object), true, uintPtrValue, uintPtrValue), + (typeof(ushort), typeof(bool), true, (ushort)1, true), + (typeof(ushort), typeof(byte), true, uint16Value, (byte) uint16Value), + (typeof(ushort), typeof(char), true, uint16Value, (char) uint16Value), + (typeof(ushort), typeof(decimal), true, uint16Value, (decimal) uint16Value), + (typeof(ushort), typeof(double), true, uint16Value, (double)uint16Value), + (typeof(ushort), typeof(short), true, uint16Value, (short)uint16Value), + (typeof(ushort), typeof(int), true, uint16Value, (int)uint16Value), + (typeof(ushort), typeof(long), true, uint16Value, (long)uint16Value), + (typeof(ushort), typeof(object), true, uint16Value, uint16Value), + (typeof(ushort), typeof(sbyte), true, uint16Value, (sbyte)uint16Value), + (typeof(ushort), typeof(float), true, uint16Value, (float)uint16Value), + (typeof(ushort), typeof(string), true, uint16Value, uint16Value.ToString(CultureInfo.InvariantCulture)), + (typeof(ushort), typeof(TestEnum), true, (ushort)enumValue, enumValue), + (typeof(ushort), typeof(ushort), true, uint16Value, uint16Value), + (typeof(ushort), typeof(uint), true, uint16Value, (uint)uint16Value), + (typeof(ushort), typeof(ulong), true, uint16Value, (ulong)uint16Value), + (typeof(uint), typeof(bool), true, (uint)1, true), + (typeof(uint), typeof(byte), true, uint32Value, (byte) uint32Value), + (typeof(uint), typeof(char), true, uint32Value, (char) uint32Value), + (typeof(uint), typeof(decimal), true, uint32Value, (decimal) uint32Value), + (typeof(uint), typeof(double), true, uint32Value, (double)uint32Value), + (typeof(uint), typeof(int), true, uint32Value, (int)uint32Value), + (typeof(uint), typeof(int), true, uint32Value, (int)uint32Value), + (typeof(uint), typeof(long), true, uint32Value, (long)uint32Value), + (typeof(uint), typeof(object), true, uint32Value, uint32Value), + (typeof(uint), typeof(sbyte), true, uint32Value, (sbyte)uint32Value), + (typeof(uint), typeof(float), true, uint32Value, (float)uint32Value), + (typeof(uint), typeof(string), true, uint32Value, uint32Value.ToString(CultureInfo.InvariantCulture)), + (typeof(uint), typeof(TestEnum), true, (uint)enumValue, enumValue), + (typeof(uint), typeof(ushort), true, uint32Value, (ushort)uint32Value), + (typeof(uint), typeof(uint), true, uint32Value, uint32Value), + (typeof(uint), typeof(ulong), true, uint32Value, (ulong)uint32Value), + (typeof(ulong), typeof(bool), true, (ulong)1, true), + (typeof(ulong), typeof(byte), true, uint64Value, (byte) uint64Value), + (typeof(ulong), typeof(char), true, uint64Value, (char) uint64Value), + (typeof(ulong), typeof(decimal), true, uint64Value, (decimal) uint64Value), + (typeof(ulong), typeof(double), true, uint64Value, (double)uint64Value), + (typeof(ulong), typeof(short), true, uint64Value, (short)uint64Value), + (typeof(ulong), typeof(int), true, uint64Value, (int)uint64Value), + (typeof(ulong), typeof(long), true, uint64Value, (long)uint64Value), + (typeof(ulong), typeof(object), true, uint64Value, uint64Value), + (typeof(ulong), typeof(sbyte), true, uint64Value, (sbyte)uint64Value), + (typeof(ulong), typeof(float), true, uint64Value, (float)uint64Value), + (typeof(ulong), typeof(string), true, uint64Value, uint64Value.ToString(CultureInfo.InvariantCulture)), + (typeof(ulong), typeof(TestEnum), true, (ulong)enumValue, enumValue), + (typeof(ulong), typeof(ushort), true, uint64Value, (ushort)uint64Value), + (typeof(ulong), typeof(uint), true, uint64Value, (uint)uint64Value), + (typeof(ulong), typeof(ulong), true, uint64Value, uint64Value), + (typeof(UIntPtr), typeof(object), true, uintPtrValue, uintPtrValue), (typeof(UIntPtr), typeof(UIntPtr), true, uintPtrValue, uintPtrValue), - (typeof(Char), typeof(Guid), false, charValue, null), - (typeof(Int32), typeof(Guid), false, int32Value, null), + (typeof(char), typeof(Guid), false, charValue, null), + (typeof(int), typeof(Guid), false, int32Value, null), (typeof(DateTime), typeof(Guid), false, dateTimeValue, null), (typeof(Guid), typeof(DateTime), false, guidValue, null), (typeof(DateOnly), typeof(DateTime), false, dateOnlyValue, null), diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlDatabaseAdapterTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlDatabaseAdapterTests.cs index ca7e26b..0bb8156 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlDatabaseAdapterTests.cs @@ -9,7 +9,7 @@ public void BindParameterValue_BytesValue_ShouldSetDbTypeAndValue() { var parameter = Substitute.For(); - var value = Generate.Single(); + var value = Generate.Single(); this.adapter.BindParameterValue(parameter, value); @@ -51,7 +51,7 @@ public void BindParameterValue_EnumValue_EnumSerializationModeIsIntegers_ShouldB .Should().Be(DbType.Int32); parameter.Value - .Should().Be((Int32)enumValue); + .Should().Be((int)enumValue); } [Fact] @@ -124,37 +124,37 @@ public void GetDataType_EnumType_EnumSerializationModeIsString_ShouldReturnVarch } [Theory] - [InlineData(typeof(Boolean?), "TINYINT(1)")] - [InlineData(typeof(Boolean), "TINYINT(1)")] - [InlineData(typeof(Byte?), "TINYINT UNSIGNED")] - [InlineData(typeof(Byte), "TINYINT UNSIGNED")] - [InlineData(typeof(Byte[]), "BLOB")] - [InlineData(typeof(Char?), "CHAR(1)")] - [InlineData(typeof(Char), "CHAR(1)")] + [InlineData(typeof(bool?), "TINYINT(1)")] + [InlineData(typeof(bool), "TINYINT(1)")] + [InlineData(typeof(byte?), "TINYINT UNSIGNED")] + [InlineData(typeof(byte), "TINYINT UNSIGNED")] + [InlineData(typeof(byte[]), "BLOB")] + [InlineData(typeof(char?), "CHAR(1)")] + [InlineData(typeof(char), "CHAR(1)")] [InlineData(typeof(DateOnly?), "DATE")] [InlineData(typeof(DateOnly), "DATE")] [InlineData(typeof(DateTime?), "DATETIME")] [InlineData(typeof(DateTime), "DATETIME")] - [InlineData(typeof(Decimal?), "DECIMAL(65,30)")] - [InlineData(typeof(Decimal), "DECIMAL(65,30)")] - [InlineData(typeof(Double?), "DOUBLE")] - [InlineData(typeof(Double), "DOUBLE")] + [InlineData(typeof(decimal?), "DECIMAL(65,30)")] + [InlineData(typeof(decimal), "DECIMAL(65,30)")] + [InlineData(typeof(double?), "DOUBLE")] + [InlineData(typeof(double), "DOUBLE")] [InlineData(typeof(Guid?), "CHAR(36)")] [InlineData(typeof(Guid), "CHAR(36)")] - [InlineData(typeof(Int16?), "SMALLINT")] - [InlineData(typeof(Int16), "SMALLINT")] - [InlineData(typeof(Int32?), "INT")] - [InlineData(typeof(Int32), "INT")] - [InlineData(typeof(Int64?), "BIGINT")] - [InlineData(typeof(Int64), "BIGINT")] - [InlineData(typeof(Single?), "FLOAT")] - [InlineData(typeof(Single), "FLOAT")] - [InlineData(typeof(String), "TEXT")] + [InlineData(typeof(short?), "SMALLINT")] + [InlineData(typeof(short), "SMALLINT")] + [InlineData(typeof(int?), "INT")] + [InlineData(typeof(int), "INT")] + [InlineData(typeof(long?), "BIGINT")] + [InlineData(typeof(long), "BIGINT")] + [InlineData(typeof(float?), "FLOAT")] + [InlineData(typeof(float), "FLOAT")] + [InlineData(typeof(string), "TEXT")] [InlineData(typeof(TimeOnly?), "TIME")] [InlineData(typeof(TimeOnly), "TIME")] [InlineData(typeof(TimeSpan?), "TIME")] [InlineData(typeof(TimeSpan), "TIME")] - public void GetDataType_SupportedTypeType_ShouldReturnMySqlDataType(Type type, String expectedResult) => + public void GetDataType_SupportedTypeType_ShouldReturnMySqlDataType(Type type, string expectedResult) => this.adapter.GetDataType(type, EnumSerializationMode.Strings) .Should().Be(expectedResult); @@ -186,7 +186,7 @@ public void ShouldGuardAgainstNullArguments() ); ArgumentNullGuardVerifier.Verify(() => - this.adapter.GetDataType(typeof(Int32), EnumSerializationMode.Integers) + this.adapter.GetDataType(typeof(int), EnumSerializationMode.Integers) ); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlTemporaryTableBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlTemporaryTableBuilderTests.cs index eb7f7f7..1e1c562 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlTemporaryTableBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlTemporaryTableBuilderTests.cs @@ -8,12 +8,12 @@ public class MySqlTemporaryTableBuilderTests : UnitTestsBase public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() { Invoking(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) ) .Should().Throw(); Invoking(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) ) .Should().Throw(); } @@ -22,12 +22,12 @@ public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() public async Task BuildTemporaryTableAsync_NameIsNullOrEmptyOrWhitespace_ShouldThrow() { await Invoking(() => - this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) ) .Should().ThrowAsync(); await Invoking(() => - this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, " ", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) ) .Should().ThrowAsync(); } @@ -40,11 +40,11 @@ public void ShouldGuardAgainstNullArguments() ); ArgumentNullGuardVerifier.Verify(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) ); ArgumentNullGuardVerifier.Verify(() => - this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) ); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs index 91bde5b..230ea95 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs @@ -15,7 +15,7 @@ public void BindParameterValue_BytesValue_ShouldSetDbTypeAndValue() { var parameter = Substitute.For(); - var value = Generate.Single(); + var value = Generate.Single(); this.adapter.BindParameterValue(parameter, value); @@ -73,7 +73,7 @@ public void BindParameterValue_EnumValue_EnumSerializationModeIsIntegers_ShouldB .Should().Be(DbType.Int32); parameter.Value - .Should().Be((Int32)enumValue); + .Should().Be((int)enumValue); } [Fact] @@ -181,39 +181,39 @@ public void GetDataType_EnumType_EnumSerializationModeIsString_ShouldReturnNVarc } [Theory] - [InlineData(typeof(Boolean?), "NUMBER(1)")] - [InlineData(typeof(Boolean), "NUMBER(1)")] - [InlineData(typeof(Byte), "NUMBER(3)")] - [InlineData(typeof(Byte?), "NUMBER(3)")] - [InlineData(typeof(Byte[]), "RAW(2000)")] - [InlineData(typeof(Char?), "CHAR(1)")] - [InlineData(typeof(Char), "CHAR(1)")] + [InlineData(typeof(bool?), "NUMBER(1)")] + [InlineData(typeof(bool), "NUMBER(1)")] + [InlineData(typeof(byte), "NUMBER(3)")] + [InlineData(typeof(byte?), "NUMBER(3)")] + [InlineData(typeof(byte[]), "RAW(2000)")] + [InlineData(typeof(char?), "CHAR(1)")] + [InlineData(typeof(char), "CHAR(1)")] [InlineData(typeof(DateOnly?), "DATE")] [InlineData(typeof(DateOnly), "DATE")] [InlineData(typeof(DateTimeOffset?), "TIMESTAMP WITH TIME ZONE")] [InlineData(typeof(DateTimeOffset), "TIMESTAMP WITH TIME ZONE")] [InlineData(typeof(DateTime?), "TIMESTAMP")] [InlineData(typeof(DateTime), "TIMESTAMP")] - [InlineData(typeof(Decimal?), "NUMBER(28,10)")] - [InlineData(typeof(Decimal), "NUMBER(28,10)")] - [InlineData(typeof(Double?), "BINARY_DOUBLE")] - [InlineData(typeof(Double), "BINARY_DOUBLE")] + [InlineData(typeof(decimal?), "NUMBER(28,10)")] + [InlineData(typeof(decimal), "NUMBER(28,10)")] + [InlineData(typeof(double?), "BINARY_DOUBLE")] + [InlineData(typeof(double), "BINARY_DOUBLE")] [InlineData(typeof(Guid?), "RAW(16)")] [InlineData(typeof(Guid), "RAW(16)")] - [InlineData(typeof(Int16?), "NUMBER(5)")] - [InlineData(typeof(Int16), "NUMBER(5)")] - [InlineData(typeof(Int32?), "NUMBER(10)")] - [InlineData(typeof(Int32), "NUMBER(10)")] - [InlineData(typeof(Int64?), "NUMBER(19)")] - [InlineData(typeof(Int64), "NUMBER(19)")] - [InlineData(typeof(Single?), "BINARY_FLOAT")] - [InlineData(typeof(Single), "BINARY_FLOAT")] - [InlineData(typeof(String), "NVARCHAR2(2000)")] + [InlineData(typeof(short?), "NUMBER(5)")] + [InlineData(typeof(short), "NUMBER(5)")] + [InlineData(typeof(int?), "NUMBER(10)")] + [InlineData(typeof(int), "NUMBER(10)")] + [InlineData(typeof(long?), "NUMBER(19)")] + [InlineData(typeof(long), "NUMBER(19)")] + [InlineData(typeof(float?), "BINARY_FLOAT")] + [InlineData(typeof(float), "BINARY_FLOAT")] + [InlineData(typeof(string), "NVARCHAR2(2000)")] [InlineData(typeof(TimeOnly?), "INTERVAL DAY TO SECOND")] [InlineData(typeof(TimeOnly), "INTERVAL DAY TO SECOND")] [InlineData(typeof(TimeSpan?), "INTERVAL DAY TO SECOND")] [InlineData(typeof(TimeSpan), "INTERVAL DAY TO SECOND")] - public void GetDataType_SupportedTypeType_ShouldReturnSqlServerDataType(Type type, String expectedResult) => + public void GetDataType_SupportedTypeType_ShouldReturnSqlServerDataType(Type type, string expectedResult) => this.adapter.GetDataType(type, EnumSerializationMode.Strings) .Should().Be(expectedResult); @@ -252,34 +252,34 @@ public void GetDbType_EnumType_EnumSerializationModeIsString_ShouldReturnString( } [Theory] - [InlineData(typeof(Boolean?), DbType.Boolean)] - [InlineData(typeof(Boolean), DbType.Boolean)] - [InlineData(typeof(Byte), DbType.Byte)] - [InlineData(typeof(Byte?), DbType.Byte)] - [InlineData(typeof(Byte[]), DbType.Binary)] - [InlineData(typeof(Char?), DbType.StringFixedLength)] - [InlineData(typeof(Char), DbType.StringFixedLength)] + [InlineData(typeof(bool?), DbType.Boolean)] + [InlineData(typeof(bool), DbType.Boolean)] + [InlineData(typeof(byte), DbType.Byte)] + [InlineData(typeof(byte?), DbType.Byte)] + [InlineData(typeof(byte[]), DbType.Binary)] + [InlineData(typeof(char?), DbType.StringFixedLength)] + [InlineData(typeof(char), DbType.StringFixedLength)] [InlineData(typeof(DateOnly?), DbType.Date)] [InlineData(typeof(DateOnly), DbType.Date)] [InlineData(typeof(DateTimeOffset?), DbType.DateTimeOffset)] [InlineData(typeof(DateTimeOffset), DbType.DateTimeOffset)] [InlineData(typeof(DateTime?), DbType.DateTime)] [InlineData(typeof(DateTime), DbType.DateTime)] - [InlineData(typeof(Decimal?), DbType.Decimal)] - [InlineData(typeof(Decimal), DbType.Decimal)] - [InlineData(typeof(Double?), DbType.Double)] - [InlineData(typeof(Double), DbType.Double)] + [InlineData(typeof(decimal?), DbType.Decimal)] + [InlineData(typeof(decimal), DbType.Decimal)] + [InlineData(typeof(double?), DbType.Double)] + [InlineData(typeof(double), DbType.Double)] [InlineData(typeof(Guid?), DbType.Guid)] [InlineData(typeof(Guid), DbType.Guid)] - [InlineData(typeof(Int16?), DbType.Int16)] - [InlineData(typeof(Int16), DbType.Int16)] - [InlineData(typeof(Int32?), DbType.Int32)] - [InlineData(typeof(Int32), DbType.Int32)] - [InlineData(typeof(Int64?), DbType.Int64)] - [InlineData(typeof(Int64), DbType.Int64)] - [InlineData(typeof(Single?), DbType.Single)] - [InlineData(typeof(Single), DbType.Single)] - [InlineData(typeof(String), DbType.String)] + [InlineData(typeof(short?), DbType.Int16)] + [InlineData(typeof(short), DbType.Int16)] + [InlineData(typeof(int?), DbType.Int32)] + [InlineData(typeof(int), DbType.Int32)] + [InlineData(typeof(long?), DbType.Int64)] + [InlineData(typeof(long), DbType.Int64)] + [InlineData(typeof(float?), DbType.Single)] + [InlineData(typeof(float), DbType.Single)] + [InlineData(typeof(string), DbType.String)] [InlineData(typeof(TimeOnly?), DbType.Time)] [InlineData(typeof(TimeOnly), DbType.Time)] [InlineData(typeof(TimeSpan?), DbType.Time)] diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleTemporaryTableBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleTemporaryTableBuilderTests.cs index c478281..6f38992 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleTemporaryTableBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleTemporaryTableBuilderTests.cs @@ -9,7 +9,7 @@ public void BuildTemporaryTable_AllowTemporaryTablesIsFalse_ShouldThrow() { OracleDatabaseAdapter.AllowTemporaryTables = false; - Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(Int32)) + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) ) .Should().Throw() .WithMessage( @@ -24,12 +24,12 @@ public void BuildTemporaryTable_AllowTemporaryTablesIsFalse_ShouldThrow() public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() { Invoking(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) ) .Should().Throw(); Invoking(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) ) .Should().Throw(); } @@ -44,7 +44,7 @@ public Task BuildTemporaryTableAsync_AllowTemporaryTablesIsFalse_ShouldThrow() null, "Name", new[] { 1 }, - typeof(Int32) + typeof(int) ) ) .Should().ThrowAsync() @@ -60,12 +60,12 @@ public Task BuildTemporaryTableAsync_AllowTemporaryTablesIsFalse_ShouldThrow() public async Task BuildTemporaryTableAsync_NameIsNullOrEmptyOrWhitespace_ShouldThrow() { await Invoking(() => - this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) ) .Should().ThrowAsync(); await Invoking(() => - this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, " ", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) ) .Should().ThrowAsync(); } @@ -78,11 +78,11 @@ public void ShouldGuardAgainstNullArguments() ); ArgumentNullGuardVerifier.Verify(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) ); ArgumentNullGuardVerifier.Verify(() => - this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) ); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlDatabaseAdapterTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlDatabaseAdapterTests.cs index 74e0776..4bcacc4 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlDatabaseAdapterTests.cs @@ -10,7 +10,7 @@ public void BindParameterValue_BytesValue_ShouldSetDbTypeAndValue() { var parameter = Substitute.For(); - var value = Generate.Single(); + var value = Generate.Single(); this.adapter.BindParameterValue(parameter, value); @@ -52,7 +52,7 @@ public void BindParameterValue_EnumValue_EnumSerializationModeIsIntegers_ShouldB .Should().Be(DbType.Int32); parameter.Value - .Should().Be((Int32)enumValue); + .Should().Be((int)enumValue); } [Fact] @@ -125,37 +125,37 @@ public void GetDataType_EnumType_EnumSerializationModeIsString_ShouldReturnChara } [Theory] - [InlineData(typeof(Boolean?), "boolean")] - [InlineData(typeof(Boolean), "boolean")] - [InlineData(typeof(Byte?), "smallint")] - [InlineData(typeof(Byte), "smallint")] - [InlineData(typeof(Byte[]), "bytea")] - [InlineData(typeof(Char?), "char(1)")] - [InlineData(typeof(Char), "char(1)")] + [InlineData(typeof(bool?), "boolean")] + [InlineData(typeof(bool), "boolean")] + [InlineData(typeof(byte?), "smallint")] + [InlineData(typeof(byte), "smallint")] + [InlineData(typeof(byte[]), "bytea")] + [InlineData(typeof(char?), "char(1)")] + [InlineData(typeof(char), "char(1)")] [InlineData(typeof(DateOnly?), "date")] [InlineData(typeof(DateOnly), "date")] [InlineData(typeof(DateTime?), "timestamp without time zone")] [InlineData(typeof(DateTime), "timestamp without time zone")] - [InlineData(typeof(Decimal?), "decimal")] - [InlineData(typeof(Decimal), "decimal")] - [InlineData(typeof(Double?), "double precision")] - [InlineData(typeof(Double), "double precision")] + [InlineData(typeof(decimal?), "decimal")] + [InlineData(typeof(decimal), "decimal")] + [InlineData(typeof(double?), "double precision")] + [InlineData(typeof(double), "double precision")] [InlineData(typeof(Guid?), "uuid")] [InlineData(typeof(Guid), "uuid")] - [InlineData(typeof(Int16?), "smallint")] - [InlineData(typeof(Int16), "smallint")] - [InlineData(typeof(Int32?), "integer")] - [InlineData(typeof(Int32), "integer")] - [InlineData(typeof(Int64?), "bigint")] - [InlineData(typeof(Int64), "bigint")] - [InlineData(typeof(Single?), "real")] - [InlineData(typeof(Single), "real")] - [InlineData(typeof(String), "text")] + [InlineData(typeof(short?), "smallint")] + [InlineData(typeof(short), "smallint")] + [InlineData(typeof(int?), "integer")] + [InlineData(typeof(int), "integer")] + [InlineData(typeof(long?), "bigint")] + [InlineData(typeof(long), "bigint")] + [InlineData(typeof(float?), "real")] + [InlineData(typeof(float), "real")] + [InlineData(typeof(string), "text")] [InlineData(typeof(TimeOnly?), "time")] [InlineData(typeof(TimeOnly), "time")] [InlineData(typeof(TimeSpan?), "interval")] [InlineData(typeof(TimeSpan), "interval")] - public void GetDataType_SupportedTypeType_ShouldReturnPostgreSqlDataType(Type type, String expectedResult) => + public void GetDataType_SupportedTypeType_ShouldReturnPostgreSqlDataType(Type type, string expectedResult) => this.adapter.GetDataType(type, EnumSerializationMode.Strings) .Should().Be(expectedResult); @@ -166,32 +166,32 @@ public void GetDataType_UnsupportedType_ShouldThrow() => .WithMessage($"Could not map the type {typeof(Entity)} to a PostgreSQL data type.*"); [Theory] - [InlineData(typeof(Boolean?), NpgsqlDbType.Boolean)] - [InlineData(typeof(Boolean), NpgsqlDbType.Boolean)] - [InlineData(typeof(Byte?), NpgsqlDbType.Smallint)] - [InlineData(typeof(Byte), NpgsqlDbType.Smallint)] - [InlineData(typeof(Byte[]), NpgsqlDbType.Bytea)] - [InlineData(typeof(Char?), NpgsqlDbType.Char)] - [InlineData(typeof(Char), NpgsqlDbType.Char)] + [InlineData(typeof(bool?), NpgsqlDbType.Boolean)] + [InlineData(typeof(bool), NpgsqlDbType.Boolean)] + [InlineData(typeof(byte?), NpgsqlDbType.Smallint)] + [InlineData(typeof(byte), NpgsqlDbType.Smallint)] + [InlineData(typeof(byte[]), NpgsqlDbType.Bytea)] + [InlineData(typeof(char?), NpgsqlDbType.Char)] + [InlineData(typeof(char), NpgsqlDbType.Char)] [InlineData(typeof(DateOnly?), NpgsqlDbType.Date)] [InlineData(typeof(DateOnly), NpgsqlDbType.Date)] [InlineData(typeof(DateTime?), NpgsqlDbType.Timestamp)] [InlineData(typeof(DateTime), NpgsqlDbType.Timestamp)] - [InlineData(typeof(Decimal?), NpgsqlDbType.Numeric)] - [InlineData(typeof(Decimal), NpgsqlDbType.Numeric)] - [InlineData(typeof(Double?), NpgsqlDbType.Double)] - [InlineData(typeof(Double), NpgsqlDbType.Double)] + [InlineData(typeof(decimal?), NpgsqlDbType.Numeric)] + [InlineData(typeof(decimal), NpgsqlDbType.Numeric)] + [InlineData(typeof(double?), NpgsqlDbType.Double)] + [InlineData(typeof(double), NpgsqlDbType.Double)] [InlineData(typeof(Guid?), NpgsqlDbType.Uuid)] [InlineData(typeof(Guid), NpgsqlDbType.Uuid)] - [InlineData(typeof(Int16?), NpgsqlDbType.Smallint)] - [InlineData(typeof(Int16), NpgsqlDbType.Smallint)] - [InlineData(typeof(Int32?), NpgsqlDbType.Integer)] - [InlineData(typeof(Int32), NpgsqlDbType.Integer)] - [InlineData(typeof(Int64?), NpgsqlDbType.Bigint)] - [InlineData(typeof(Int64), NpgsqlDbType.Bigint)] - [InlineData(typeof(Single?), NpgsqlDbType.Real)] - [InlineData(typeof(Single), NpgsqlDbType.Real)] - [InlineData(typeof(String), NpgsqlDbType.Text)] + [InlineData(typeof(short?), NpgsqlDbType.Smallint)] + [InlineData(typeof(short), NpgsqlDbType.Smallint)] + [InlineData(typeof(int?), NpgsqlDbType.Integer)] + [InlineData(typeof(int), NpgsqlDbType.Integer)] + [InlineData(typeof(long?), NpgsqlDbType.Bigint)] + [InlineData(typeof(long), NpgsqlDbType.Bigint)] + [InlineData(typeof(float?), NpgsqlDbType.Real)] + [InlineData(typeof(float), NpgsqlDbType.Real)] + [InlineData(typeof(string), NpgsqlDbType.Text)] [InlineData(typeof(TimeOnly?), NpgsqlDbType.Time)] [InlineData(typeof(TimeOnly), NpgsqlDbType.Time)] [InlineData(typeof(TimeSpan?), NpgsqlDbType.Interval)] @@ -228,11 +228,11 @@ public void ShouldGuardAgainstNullArguments() ); ArgumentNullGuardVerifier.Verify(() => - this.adapter.GetDataType(typeof(Int32), EnumSerializationMode.Integers) + this.adapter.GetDataType(typeof(int), EnumSerializationMode.Integers) ); ArgumentNullGuardVerifier.Verify(() => - this.adapter.GetDbType(typeof(Int32), EnumSerializationMode.Integers) + this.adapter.GetDbType(typeof(int), EnumSerializationMode.Integers) ); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlTemporaryTableBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlTemporaryTableBuilderTests.cs index d6db9a5..3c0bc92 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlTemporaryTableBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlTemporaryTableBuilderTests.cs @@ -8,12 +8,12 @@ public class PostgreSqlTemporaryTableBuilderTests : UnitTestsBase public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() { Invoking(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) ) .Should().Throw(); Invoking(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) ) .Should().Throw(); } @@ -22,12 +22,12 @@ public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() public async Task BuildTemporaryTableAsync_NameIsNullOrEmptyOrWhitespace_ShouldThrow() { await Invoking(() => - this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) ) .Should().ThrowAsync(); await Invoking(() => - this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, " ", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) ) .Should().ThrowAsync(); } @@ -40,11 +40,11 @@ public void ShouldGuardAgainstNullArguments() ); ArgumentNullGuardVerifier.Verify(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) ); ArgumentNullGuardVerifier.Verify(() => - this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) ); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerDatabaseAdapterTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerDatabaseAdapterTests.cs index 5fd8c0e..3ee9d1b 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerDatabaseAdapterTests.cs @@ -9,7 +9,7 @@ public void BindParameterValue_BytesValue_ShouldSetDbTypeAndValue() { var parameter = Substitute.For(); - var value = Generate.Single(); + var value = Generate.Single(); this.adapter.BindParameterValue(parameter, value); @@ -51,7 +51,7 @@ public void BindParameterValue_EnumValue_EnumSerializationModeIsIntegers_ShouldB .Should().Be(DbType.Int32); parameter.Value - .Should().Be((Int32)enumValue); + .Should().Be((int)enumValue); } [Fact] @@ -124,40 +124,40 @@ public void GetDataType_EnumType_EnumSerializationModeIsString_ShouldReturnNVarc } [Theory] - [InlineData(typeof(Boolean?), "bit")] - [InlineData(typeof(Boolean), "bit")] - [InlineData(typeof(Byte), "tinyint")] - [InlineData(typeof(Byte?), "tinyint")] - [InlineData(typeof(Byte[]), "varbinary(max)")] - [InlineData(typeof(Char?), "char(1)")] - [InlineData(typeof(Char), "char(1)")] + [InlineData(typeof(bool?), "bit")] + [InlineData(typeof(bool), "bit")] + [InlineData(typeof(byte), "tinyint")] + [InlineData(typeof(byte?), "tinyint")] + [InlineData(typeof(byte[]), "varbinary(max)")] + [InlineData(typeof(char?), "char(1)")] + [InlineData(typeof(char), "char(1)")] [InlineData(typeof(DateOnly?), "date")] [InlineData(typeof(DateOnly), "date")] [InlineData(typeof(DateTimeOffset?), "datetimeoffset")] [InlineData(typeof(DateTimeOffset), "datetimeoffset")] [InlineData(typeof(DateTime?), "datetime2")] [InlineData(typeof(DateTime), "datetime2")] - [InlineData(typeof(Decimal?), "decimal(28,10)")] - [InlineData(typeof(Decimal), "decimal(28,10)")] - [InlineData(typeof(Double?), "float")] - [InlineData(typeof(Double), "float")] + [InlineData(typeof(decimal?), "decimal(28,10)")] + [InlineData(typeof(decimal), "decimal(28,10)")] + [InlineData(typeof(double?), "float")] + [InlineData(typeof(double), "float")] [InlineData(typeof(Guid?), "uniqueidentifier")] [InlineData(typeof(Guid), "uniqueidentifier")] - [InlineData(typeof(Int16?), "smallint")] - [InlineData(typeof(Int16), "smallint")] - [InlineData(typeof(Int32?), "int")] - [InlineData(typeof(Int32), "int")] - [InlineData(typeof(Int64?), "bigint")] - [InlineData(typeof(Int64), "bigint")] - [InlineData(typeof(Object), "sql_variant")] - [InlineData(typeof(Single?), "real")] - [InlineData(typeof(Single), "real")] - [InlineData(typeof(String), "nvarchar(max)")] + [InlineData(typeof(short?), "smallint")] + [InlineData(typeof(short), "smallint")] + [InlineData(typeof(int?), "int")] + [InlineData(typeof(int), "int")] + [InlineData(typeof(long?), "bigint")] + [InlineData(typeof(long), "bigint")] + [InlineData(typeof(object), "sql_variant")] + [InlineData(typeof(float?), "real")] + [InlineData(typeof(float), "real")] + [InlineData(typeof(string), "nvarchar(max)")] [InlineData(typeof(TimeOnly?), "time")] [InlineData(typeof(TimeOnly), "time")] [InlineData(typeof(TimeSpan?), "time")] [InlineData(typeof(TimeSpan), "time")] - public void GetDataType_SupportedTypeType_ShouldReturnSqlServerDataType(Type type, String expectedResult) => + public void GetDataType_SupportedTypeType_ShouldReturnSqlServerDataType(Type type, string expectedResult) => this.adapter.GetDataType(type, EnumSerializationMode.Strings) .Should().Be(expectedResult); @@ -189,7 +189,7 @@ public void ShouldGuardAgainstNullArguments() ); ArgumentNullGuardVerifier.Verify(() => - this.adapter.GetDataType(typeof(Int32), EnumSerializationMode.Integers) + this.adapter.GetDataType(typeof(int), EnumSerializationMode.Integers) ); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerTemporaryTableBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerTemporaryTableBuilderTests.cs index 1f782a2..e067cb0 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerTemporaryTableBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerTemporaryTableBuilderTests.cs @@ -8,12 +8,12 @@ public class SqlServerTemporaryTableBuilderTests : UnitTestsBase public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() { Invoking(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) ) .Should().Throw(); Invoking(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) ) .Should().Throw(); } @@ -22,12 +22,12 @@ public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() public async Task BuildTemporaryTableAsync_NameIsNullOrEmptyOrWhitespace_ShouldThrow() { await Invoking(() => - this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) ) .Should().ThrowAsync(); await Invoking(() => - this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, " ", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) ) .Should().ThrowAsync(); } @@ -40,11 +40,11 @@ public void ShouldGuardAgainstNullArguments() ); ArgumentNullGuardVerifier.Verify(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) ); ArgumentNullGuardVerifier.Verify(() => - this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) ); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteDatabaseAdapterTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteDatabaseAdapterTests.cs index 004bdf4..6db13aa 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteDatabaseAdapterTests.cs @@ -9,7 +9,7 @@ public void BindParameterValue_BytesValue_ShouldSetDbTypeAndValue() { var parameter = Substitute.For(); - var value = Generate.Single(); + var value = Generate.Single(); this.adapter.BindParameterValue(parameter, value); @@ -51,7 +51,7 @@ public void BindParameterValue_EnumValue_EnumSerializationModeIsIntegers_ShouldB .Should().Be(DbType.Int32); parameter.Value - .Should().Be((Int32)enumValue); + .Should().Be((int)enumValue); } [Fact] @@ -124,39 +124,39 @@ public void GetDataType_EnumType_EnumSerializationModeIsString_ShouldReturnText( } [Theory] - [InlineData(typeof(Boolean?), "INTEGER")] - [InlineData(typeof(Boolean), "INTEGER")] - [InlineData(typeof(Byte?), "INTEGER")] - [InlineData(typeof(Byte), "INTEGER")] - [InlineData(typeof(Byte[]), "BLOB")] - [InlineData(typeof(Char?), "TEXT")] - [InlineData(typeof(Char), "TEXT")] + [InlineData(typeof(bool?), "INTEGER")] + [InlineData(typeof(bool), "INTEGER")] + [InlineData(typeof(byte?), "INTEGER")] + [InlineData(typeof(byte), "INTEGER")] + [InlineData(typeof(byte[]), "BLOB")] + [InlineData(typeof(char?), "TEXT")] + [InlineData(typeof(char), "TEXT")] [InlineData(typeof(DateOnly?), "TEXT")] [InlineData(typeof(DateOnly), "TEXT")] [InlineData(typeof(DateTime?), "TEXT")] [InlineData(typeof(DateTime), "TEXT")] [InlineData(typeof(DateTimeOffset?), "TEXT")] [InlineData(typeof(DateTimeOffset), "TEXT")] - [InlineData(typeof(Decimal?), "TEXT")] - [InlineData(typeof(Decimal), "TEXT")] - [InlineData(typeof(Double?), "REAL")] - [InlineData(typeof(Double), "REAL")] + [InlineData(typeof(decimal?), "TEXT")] + [InlineData(typeof(decimal), "TEXT")] + [InlineData(typeof(double?), "REAL")] + [InlineData(typeof(double), "REAL")] [InlineData(typeof(Guid?), "TEXT")] [InlineData(typeof(Guid), "TEXT")] - [InlineData(typeof(Int16?), "INTEGER")] - [InlineData(typeof(Int16), "INTEGER")] - [InlineData(typeof(Int32?), "INTEGER")] - [InlineData(typeof(Int32), "INTEGER")] - [InlineData(typeof(Int64?), "INTEGER")] - [InlineData(typeof(Int64), "INTEGER")] - [InlineData(typeof(Single?), "REAL")] - [InlineData(typeof(Single), "REAL")] - [InlineData(typeof(String), "TEXT")] + [InlineData(typeof(short?), "INTEGER")] + [InlineData(typeof(short), "INTEGER")] + [InlineData(typeof(int?), "INTEGER")] + [InlineData(typeof(int), "INTEGER")] + [InlineData(typeof(long?), "INTEGER")] + [InlineData(typeof(long), "INTEGER")] + [InlineData(typeof(float?), "REAL")] + [InlineData(typeof(float), "REAL")] + [InlineData(typeof(string), "TEXT")] [InlineData(typeof(TimeOnly?), "TEXT")] [InlineData(typeof(TimeOnly), "TEXT")] [InlineData(typeof(TimeSpan?), "TEXT")] [InlineData(typeof(TimeSpan), "TEXT")] - public void GetDataType_SupportedTypeType_ShouldReturnSqliteDataType(Type type, String expectedResult) => + public void GetDataType_SupportedTypeType_ShouldReturnSqliteDataType(Type type, string expectedResult) => this.adapter.GetDataType(type, EnumSerializationMode.Strings) .Should().Be(expectedResult); @@ -188,7 +188,7 @@ public void ShouldGuardAgainstNullArguments() ); ArgumentNullGuardVerifier.Verify(() => - this.adapter.GetDataType(typeof(Int32), EnumSerializationMode.Integers) + this.adapter.GetDataType(typeof(int), EnumSerializationMode.Integers) ); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteTemporaryTableBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteTemporaryTableBuilderTests.cs index ef3474e..4dda894 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteTemporaryTableBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteTemporaryTableBuilderTests.cs @@ -8,12 +8,12 @@ public class SqliteTemporaryTableBuilderTests : UnitTestsBase public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() { Invoking(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) ) .Should().Throw(); Invoking(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) ) .Should().Throw(); } @@ -22,12 +22,12 @@ public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() public async Task BuildTemporaryTableAsync_NameIsNullOrEmptyOrWhitespace_ShouldThrow() { await Invoking(() => - this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) ) .Should().ThrowAsync(); await Invoking(() => - this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, " ", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) ) .Should().ThrowAsync(); } @@ -40,11 +40,11 @@ public void ShouldGuardAgainstNullArguments() ); ArgumentNullGuardVerifier.Verify(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) ); ArgumentNullGuardVerifier.Verify(() => - this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(Int32)) + this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) ); } diff --git a/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandBuilderTests.cs index c4330ea..0c30f11 100644 --- a/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandBuilderTests.cs @@ -12,7 +12,7 @@ public class DbCommandBuilderTests : UnitTestsBase [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_CancellationToken_ShouldUseCancellationToken(Boolean useAsyncApi) + public async Task BuildDbCommand_CancellationToken_ShouldUseCancellationToken(bool useAsyncApi) { using var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; @@ -33,7 +33,7 @@ public async Task BuildDbCommand_CancellationToken_ShouldUseCancellationToken(Bo [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_Code_Parameters_ShouldStoreCodeAndParameters(Boolean useAsyncApi) + public async Task BuildDbCommand_Code_Parameters_ShouldStoreCodeAndParameters(bool useAsyncApi) { var statement = new InterpolatedSqlStatement( "Code", @@ -77,7 +77,7 @@ public async Task BuildDbCommand_Code_Parameters_ShouldStoreCodeAndParameters(Bo [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_CommandTimeout_ShouldUseCommandTimeout(Boolean useAsyncApi) + public async Task BuildDbCommand_CommandTimeout_ShouldUseCommandTimeout(bool useAsyncApi) { var timeout = Generate.Single(); @@ -90,13 +90,13 @@ public async Task BuildDbCommand_CommandTimeout_ShouldUseCommandTimeout(Boolean ); command.CommandTimeout - .Should().Be((Int32)timeout.TotalSeconds); + .Should().Be((int)timeout.TotalSeconds); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_CommandType_ShouldUseCommandType(Boolean useAsyncApi) + public async Task BuildDbCommand_CommandType_ShouldUseCommandType(bool useAsyncApi) { var (command, _) = await CallApi( useAsyncApi, @@ -113,7 +113,7 @@ public async Task BuildDbCommand_CommandType_ShouldUseCommandType(Boolean useAsy [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_InterpolatedParameter_DuplicateName_ShouldAppendSuffix(Boolean useAsyncApi) + public async Task BuildDbCommand_InterpolatedParameter_DuplicateName_ShouldAppendSuffix(bool useAsyncApi) { var value = Generate.ScalarValue(); @@ -136,7 +136,7 @@ public async Task BuildDbCommand_InterpolatedParameter_DuplicateName_ShouldAppen [InlineData(true)] public async Task BuildDbCommand_InterpolatedParameter_EnumValue_EnumSerializationModeIsIntegers_ShouldSerializeEnumToInteger( - Boolean useAsyncApi + bool useAsyncApi ) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Integers; @@ -157,7 +157,7 @@ Boolean useAsyncApi .Should().Be("EnumValue"); command.Parameters[0].Value - .Should().Be((Int32)enumValue); + .Should().Be((int)enumValue); } [Theory] @@ -165,7 +165,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task BuildDbCommand_InterpolatedParameter_EnumValue_EnumSerializationModeIsStrings_ShouldSerializeEnumToString( - Boolean useAsyncApi + bool useAsyncApi ) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Strings; @@ -192,12 +192,12 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_InterpolatedParameter_ShouldHandleNullAndNonNullValues(Boolean useAsyncApi) + public async Task BuildDbCommand_InterpolatedParameter_ShouldHandleNullAndNonNullValues(bool useAsyncApi) { - Int64? id1 = Generate.Id(); - Int64? id2 = null; - Object value1 = Generate.Single(); - Object? value2 = null; + long? id1 = Generate.Id(); + long? id2 = null; + object value1 = Generate.Single(); + object? value2 = null; var (command, _) = await CallApi( useAsyncApi, @@ -241,14 +241,14 @@ public async Task BuildDbCommand_InterpolatedParameter_ShouldHandleNullAndNonNul [InlineData(false)] [InlineData(true)] public async Task BuildDbCommand_InterpolatedParameter_ShouldInferNameFromValueExpressionIfPossible( - Boolean useAsyncApi + bool useAsyncApi ) { var productId = Generate.Id(); - static Int64 GetProductId() => Generate.Id(); + static long GetProductId() => Generate.Id(); #pragma warning disable RCS1163 // Unused parameter #pragma warning disable IDE0060 // Remove unused parameter - static Int64 GetProductIdByCategory(String category) => Generate.Id(); + static long GetProductIdByCategory(string category) => Generate.Id(); #pragma warning restore IDE0060 // Remove unused parameter #pragma warning restore RCS1163 // Unused parameter var productIds = Generate.Ids().ToArray(); @@ -304,7 +304,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_InterpolatedParameter_ShouldStoreParameter(Boolean useAsyncApi) + public async Task BuildDbCommand_InterpolatedParameter_ShouldStoreParameter(bool useAsyncApi) { var value = Generate.ScalarValue(); @@ -331,9 +331,9 @@ public async Task BuildDbCommand_InterpolatedParameter_ShouldStoreParameter(Bool [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_InterpolatedParameter_ShouldSupportComplexExpressions(Boolean useAsyncApi) + public async Task BuildDbCommand_InterpolatedParameter_ShouldSupportComplexExpressions(bool useAsyncApi) { - const Double baseDiscount = 0.1; + const double baseDiscount = 0.1; var entityIds = Generate.Ids(20); var (command, _) = await CallApi( @@ -375,7 +375,7 @@ public async Task BuildDbCommand_InterpolatedParameter_ShouldSupportComplexExpre [InlineData(true)] public async Task BuildDbCommand_InterpolatedTemporaryTable_DatabaseAdapterDoesNotSupportTemporaryTables_ShouldThrow( - Boolean useAsyncApi + bool useAsyncApi ) { var entityIds = Generate.Ids(); @@ -413,15 +413,15 @@ await Invoking(() => CallApi( [InlineData(true)] public async Task BuildDbCommand_InterpolatedTemporaryTable_ShouldInferTableNameFromValuesExpressionIfPossible( - Boolean useAsyncApi + bool useAsyncApi ) { var entityIds = Generate.Ids(); - static List Get() => Generate.Ids(); - static List GetEntityIds() => Generate.Ids(); + static List Get() => Generate.Ids(); + static List GetEntityIds() => Generate.Ids(); #pragma warning disable RCS1163 // Unused parameter #pragma warning disable IDE0060 // Remove unused parameter - static List GetEntityIdsByCategory(String category) => Generate.Ids(); + static List GetEntityIdsByCategory(string category) => Generate.Ids(); #pragma warning restore IDE0060 // Remove unused parameter #pragma warning restore RCS1163 // Unused parameter @@ -484,7 +484,7 @@ SELECT Value FROM [#{temporaryTables[4].Name}] [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_InterpolatedTemporaryTable_ShouldStoreTemporaryTable(Boolean useAsyncApi) + public async Task BuildDbCommand_InterpolatedTemporaryTable_ShouldStoreTemporaryTable(bool useAsyncApi) { var entities = Generate.Multiple(); var entityIds = Generate.Ids(); @@ -528,7 +528,7 @@ WHERE Entities.Id IN (SELECT Value FROM {TemporaryTable(entityIds)}) .Should().BeEquivalentTo(entityIds); table2.ValuesType - .Should().Be(typeof(Int64)); + .Should().Be(typeof(long)); command.CommandText .Should().Be( @@ -543,7 +543,7 @@ WHERE Entities.Id IN (SELECT Value FROM [#{table2.Name}]) [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_MultipleInterpolatedParameters_ShouldStoreParameters(Boolean useAsyncApi) + public async Task BuildDbCommand_MultipleInterpolatedParameters_ShouldStoreParameters(bool useAsyncApi) { var value1 = Generate.ScalarValue(); var value2 = Generate.ScalarValue(); @@ -587,7 +587,7 @@ public async Task BuildDbCommand_MultipleInterpolatedParameters_ShouldStoreParam [InlineData(true)] public async Task BuildDbCommand_Parameter_EnumValue_EnumSerializationModeIsIntegers_ShouldSerializeEnumToInteger( - Boolean useAsyncApi + bool useAsyncApi ) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Integers; @@ -613,7 +613,7 @@ Boolean useAsyncApi .Should().Be("Parameter1"); command.Parameters[0].Value - .Should().Be((Int32)enumValue); + .Should().Be((int)enumValue); } [Theory] @@ -621,7 +621,7 @@ Boolean useAsyncApi [InlineData(true)] public async Task BuildDbCommand_Parameter_EnumValue_EnumSerializationModeIsStrings_ShouldSerializeEnumToString( - Boolean useAsyncApi + bool useAsyncApi ) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Strings; @@ -653,7 +653,7 @@ Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_ShouldFormatAndStoreLiteral(Boolean useAsyncApi) + public async Task BuildDbCommand_ShouldFormatAndStoreLiteral(bool useAsyncApi) { var (command, _) = await CallApi( useAsyncApi, @@ -669,7 +669,7 @@ public async Task BuildDbCommand_ShouldFormatAndStoreLiteral(Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_ShouldReturnCommandDisposer(Boolean useAsyncApi) + public async Task BuildDbCommand_ShouldReturnCommandDisposer(bool useAsyncApi) { var (_, commandDisposer) = await CallApi( useAsyncApi, @@ -685,7 +685,7 @@ public async Task BuildDbCommand_ShouldReturnCommandDisposer(Boolean useAsyncApi [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_ShouldStoreLiteral(Boolean useAsyncApi) + public async Task BuildDbCommand_ShouldStoreLiteral(bool useAsyncApi) { var (command, _) = await CallApi( useAsyncApi, @@ -701,7 +701,7 @@ public async Task BuildDbCommand_ShouldStoreLiteral(Boolean useAsyncApi) [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildDbCommand_Transaction_ShouldUseTransaction(Boolean useAsyncApi) + public async Task BuildDbCommand_Transaction_ShouldUseTransaction(bool useAsyncApi) { await using var transaction = await this.MockDbConnection.BeginTransactionAsync(); @@ -718,7 +718,7 @@ public async Task BuildDbCommand_Transaction_ShouldUseTransaction(Boolean useAsy } private static Task<(DbCommand, DbCommandDisposer)> CallApi( - Boolean useAsyncApi, + bool useAsyncApi, InterpolatedSqlStatement statement, IDatabaseAdapter databaseAdapter, DbConnection connection, @@ -761,6 +761,6 @@ public async Task BuildDbCommand_Transaction_ShouldUseTransaction(Boolean useAsy } } - private readonly List testEntityIds = Generate.Ids(); - private readonly Int64 testProductId = Generate.Id(); + private readonly List testEntityIds = Generate.Ids(); + private readonly long testProductId = Generate.Id(); } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ExecuteScalarTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ExecuteScalarTests.cs index a041327..24078b0 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ExecuteScalarTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ExecuteScalarTests.cs @@ -9,7 +9,7 @@ public class DbConnectionExtensions_ExecuteScalarTests() : StatementMethodTestsB commandType, cancellationToken ) => - connection.ExecuteScalarAsync(sql, transaction, timeout, commandType, cancellationToken), + connection.ExecuteScalarAsync(sql, transaction, timeout, commandType, cancellationToken), ( connection, sql, @@ -18,18 +18,18 @@ public class DbConnectionExtensions_ExecuteScalarTests() : StatementMethodTestsB commandType, cancellationToken ) => - connection.ExecuteScalar(sql, transaction, timeout, commandType, cancellationToken) + connection.ExecuteScalar(sql, transaction, timeout, commandType, cancellationToken) ) { [Fact] public void ShouldGuardAgainstNullArguments() { ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.ExecuteScalar("SELECT 1") + this.MockDbConnection.ExecuteScalar("SELECT 1") ); ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.ExecuteScalarAsync("SELECT 1") + this.MockDbConnection.ExecuteScalarAsync("SELECT 1") ); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ParameterTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ParameterTests.cs index d01a7d0..1204c56 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ParameterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ParameterTests.cs @@ -8,9 +8,9 @@ public class DbConnectionExtensions_ParameterTests : UnitTestsBase public void Parameter_ShouldInferParameterNameFromValueExpressionIfPossible() { var productId = Generate.Id(); - static Int64 GetProductId() => Generate.Id(); + static long GetProductId() => Generate.Id(); #pragma warning disable RCS1163 // Unused parameter - static Int64 GetProductIdByCategory(String category) => Generate.Id(); + static long GetProductIdByCategory(string category) => Generate.Id(); #pragma warning restore RCS1163 // Unused parameter var productIds = Generate.Ids().ToArray(); @@ -51,12 +51,12 @@ public void Parameter_ShouldReturnInterpolatedParameter() public void Parameter_ShouldTruncateInferredParameterName() { // ReSharper disable once InconsistentNaming - const Int32 longname_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890 = 1; + const int longname_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890 = 1; Parameter(longname_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890).InferredName .Should().HaveLength(60) .And.Be("Longname_1234567890_1234567890_1234567890_1234567890_1234567"); } - private const Int64 TestProductId = 106L; + private const long TestProductId = 106L; } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOfTTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOfTTests.cs index e28322b..7999d59 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOfTTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOfTTests.cs @@ -29,7 +29,7 @@ public DbConnectionExtensions_QueryFirstOfTTests() : base( mockDbDataReader.FieldCount.Returns(1); mockDbDataReader.GetName(0).Returns("Id"); - mockDbDataReader.GetFieldType(0).Returns(typeof(Int64)); + mockDbDataReader.GetFieldType(0).Returns(typeof(long)); mockDbDataReader.Read().Returns(true); mockDbDataReader.ReadAsync(TestContext.Current.CancellationToken).Returns(true); diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOrDefaultOfTTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOrDefaultOfTTests.cs index b04bbc9..3a9bd6e 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOrDefaultOfTTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOrDefaultOfTTests.cs @@ -29,7 +29,7 @@ public DbConnectionExtensions_QueryFirstOrDefaultOfTTests() : base( mockDbDataReader.FieldCount.Returns(1); mockDbDataReader.GetName(0).Returns("Id"); - mockDbDataReader.GetFieldType(0).Returns(typeof(Int64)); + mockDbDataReader.GetFieldType(0).Returns(typeof(long)); mockDbDataReader.Read().Returns(true); mockDbDataReader.ReadAsync(TestContext.Current.CancellationToken).Returns(true); diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOrDefaultTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOrDefaultTests.cs index 7a6ee39..6e1e87e 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOrDefaultTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOrDefaultTests.cs @@ -29,7 +29,7 @@ public DbConnectionExtensions_QueryFirstOrDefaultTests() : base( mockDbDataReader.FieldCount.Returns(1); mockDbDataReader.GetName(0).Returns("Id"); - mockDbDataReader.GetFieldType(0).Returns(typeof(Int64)); + mockDbDataReader.GetFieldType(0).Returns(typeof(long)); mockDbDataReader.Read().Returns(true); mockDbDataReader.ReadAsync(TestContext.Current.CancellationToken).Returns(true); diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstTests.cs index 3090235..3972ad1 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstTests.cs @@ -29,7 +29,7 @@ public DbConnectionExtensions_QueryFirstTests() : base( mockDbDataReader.FieldCount.Returns(1); mockDbDataReader.GetName(0).Returns("Id"); - mockDbDataReader.GetFieldType(0).Returns(typeof(Int64)); + mockDbDataReader.GetFieldType(0).Returns(typeof(long)); mockDbDataReader.Read().Returns(true); mockDbDataReader.ReadAsync(TestContext.Current.CancellationToken).Returns(true); diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryOfTTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryOfTTests.cs index 1fc2331..9dda5eb 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryOfTTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryOfTTests.cs @@ -32,7 +32,7 @@ public DbConnectionExtensions_QueryOfTTests() : base( mockDbDataReader.FieldCount.Returns(1); mockDbDataReader.GetName(0).Returns("Id"); - mockDbDataReader.GetFieldType(0).Returns(typeof(Int64)); + mockDbDataReader.GetFieldType(0).Returns(typeof(long)); this.MockDbCommand.ExecuteReader(Arg.Any()) .Returns(mockDbDataReader); diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOfTTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOfTTests.cs index 365edcd..80cee1c 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOfTTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOfTTests.cs @@ -29,7 +29,7 @@ public DbConnectionExtensions_QuerySingleOfTTests() : base( mockDbDataReader.FieldCount.Returns(1); mockDbDataReader.GetName(0).Returns("Id"); - mockDbDataReader.GetFieldType(0).Returns(typeof(Int64)); + mockDbDataReader.GetFieldType(0).Returns(typeof(long)); mockDbDataReader.Read().Returns(true, false); mockDbDataReader.ReadAsync(TestContext.Current.CancellationToken).Returns(true, false); diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOrDefaultOfTTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOrDefaultOfTTests.cs index 24544e1..4b1ac1c 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOrDefaultOfTTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOrDefaultOfTTests.cs @@ -29,7 +29,7 @@ public DbConnectionExtensions_QuerySingleOrDefaultOfTTests() : base( mockDbDataReader.FieldCount.Returns(1); mockDbDataReader.GetName(0).Returns("Id"); - mockDbDataReader.GetFieldType(0).Returns(typeof(Int64)); + mockDbDataReader.GetFieldType(0).Returns(typeof(long)); mockDbDataReader.Read().Returns(true, false); mockDbDataReader.ReadAsync(TestContext.Current.CancellationToken).Returns(true, false); diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOrDefaultTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOrDefaultTests.cs index afa4d0b..4f26643 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOrDefaultTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOrDefaultTests.cs @@ -29,7 +29,7 @@ public DbConnectionExtensions_QuerySingleOrDefaultTests() : base( mockDbDataReader.FieldCount.Returns(1); mockDbDataReader.GetName(0).Returns("Id"); - mockDbDataReader.GetFieldType(0).Returns(typeof(Int64)); + mockDbDataReader.GetFieldType(0).Returns(typeof(long)); mockDbDataReader.Read().Returns(true, false); mockDbDataReader.ReadAsync(TestContext.Current.CancellationToken).Returns(true, false); diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleTests.cs index 5496899..7b60b78 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleTests.cs @@ -29,7 +29,7 @@ public DbConnectionExtensions_QuerySingleTests() : base( mockDbDataReader.FieldCount.Returns(1); mockDbDataReader.GetName(0).Returns("Id"); - mockDbDataReader.GetFieldType(0).Returns(typeof(Int64)); + mockDbDataReader.GetFieldType(0).Returns(typeof(long)); mockDbDataReader.Read().Returns(true, false); mockDbDataReader.ReadAsync(TestContext.Current.CancellationToken).Returns(true, false); diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryTests.cs index 0bccc94..aa149b6 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryTests.cs @@ -33,7 +33,7 @@ public DbConnectionExtensions_QueryTests() : base( mockDbDataReader.FieldCount.Returns(1); mockDbDataReader.GetName(0).Returns("Id"); - mockDbDataReader.GetFieldType(0).Returns(typeof(Int64)); + mockDbDataReader.GetFieldType(0).Returns(typeof(long)); this.MockDbCommand.ExecuteReader(Arg.Any()) .Returns(mockDbDataReader); diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.TemporaryTableTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.TemporaryTableTests.cs index dae1d01..4c91821 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.TemporaryTableTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.TemporaryTableTests.cs @@ -6,16 +6,16 @@ public class DbConnectionExtensions_TemporaryTableTests : UnitTestsBase { [Fact] public void ShouldGuardAgainstNullArguments() => - ArgumentNullGuardVerifier.Verify(() => TemporaryTable(new List())); + ArgumentNullGuardVerifier.Verify(() => TemporaryTable(new List())); [Fact] public void TemporaryTable_ShouldInferTableNameFromValuesExpressionIfPossible() { var entityIds = Generate.Ids(); - static List Get() => Generate.Ids(); - static List GetEntityIds() => Generate.Ids(); + static List Get() => Generate.Ids(); + static List GetEntityIds() => Generate.Ids(); #pragma warning disable RCS1163 // Unused parameter - static List GetEntityIdsByCategory(String category) => Generate.Ids(); + static List GetEntityIdsByCategory(string category) => Generate.Ids(); #pragma warning restore RCS1163 // Unused parameter TemporaryTable(entityIds).Name @@ -45,7 +45,7 @@ public void TemporaryTable_ShouldReturnInterpolatedTemporaryTable() .Should().BeSameAs(entityIds); temporaryTable1.ValuesType - .Should().Be(typeof(Int64)); + .Should().Be(typeof(long)); temporaryTable1.Name .Should().StartWith("EntityIds_"); @@ -68,7 +68,7 @@ public void TemporaryTable_ShouldReturnInterpolatedTemporaryTable() public void TemporaryTable_ShouldTruncateInferredTableName() { // ReSharper disable once InconsistentNaming - Int32[] longname_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890 = [1, 2, 3]; + int[] longname_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890 = [1, 2, 3]; TemporaryTable(longname_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890).Name .Should().HaveLength(60) @@ -77,11 +77,11 @@ public void TemporaryTable_ShouldTruncateInferredTableName() [Fact] public void TemporaryTable_TIsObject_ShouldThrow() => - Invoking(() => TemporaryTable(new List())) + Invoking(() => TemporaryTable(new List())) .Should().Throw() .WithMessage( - $"The type parameter T cannot be the type {typeof(Object)}." + $"The type parameter T cannot be the type {typeof(object)}." ); - private readonly List testEntityIds = Generate.Ids(); + private readonly List testEntityIds = Generate.Ids(); } diff --git a/tests/DbConnectionPlus.UnitTests/Dynamic/DataRowTests.cs b/tests/DbConnectionPlus.UnitTests/Dynamic/DataRowTests.cs index 5455245..8859e52 100644 --- a/tests/DbConnectionPlus.UnitTests/Dynamic/DataRowTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Dynamic/DataRowTests.cs @@ -12,7 +12,7 @@ public class DataRowTests : UnitTestsBase [Fact] public void ShouldBeMutable() { - var dictionary = new Dictionary + var dictionary = new Dictionary { { "ColumnA", Generate.ScalarValue() }, { "ColumnB", Generate.ScalarValue() }, @@ -52,7 +52,7 @@ public void ShouldBeMutable() [Fact] public void ShouldAllowDynamicMemberAccess() { - var dictionary = new Dictionary + var dictionary = new Dictionary { { "ColumnA", Generate.ScalarValue() }, { "ColumnB", Generate.ScalarValue() } @@ -60,17 +60,17 @@ public void ShouldAllowDynamicMemberAccess() dynamic dataRow = new DataRow(dictionary); - ((Object?)dataRow.ColumnA) + ((object?)dataRow.ColumnA) .Should().Be(dictionary["ColumnA"]); - ((Object?)dataRow.ColumnB) + ((object?)dataRow.ColumnB) .Should().Be(dictionary["ColumnB"]); } [Fact] public void ShouldAllowDynamicMemberAssignment() { - var dictionary = new Dictionary + var dictionary = new Dictionary { { "ColumnA", Generate.ScalarValue() } }; @@ -91,7 +91,7 @@ public void ShouldAllowDynamicMemberAssignment() [Fact] public void ShouldAllowDynamicMemberAssignmentOfUnknownColumn() { - var dataRow = new DataRow(new Dictionary()); + var dataRow = new DataRow(new Dictionary()); dynamic dynamicDataRow = dataRow; var value = Generate.ScalarValue(); @@ -104,7 +104,7 @@ public void ShouldAllowDynamicMemberAssignmentOfUnknownColumn() [Fact] public void ShouldProvideDynamicMemberNames() { - var dictionary = new Dictionary + var dictionary = new Dictionary { { "ColumnA", Generate.ScalarValue() }, { "ColumnB", Generate.ScalarValue() } @@ -121,43 +121,43 @@ public void ShouldProvideDynamicMemberNames() [Fact] public void ShouldThrowWhenDynamicallyReadingUnknownColumn() { - dynamic dataRow = new DataRow(new Dictionary()); + dynamic dataRow = new DataRow(new Dictionary()); - Invoking(() => (Object?)dataRow.UnknownColumn) + Invoking(() => (object?)dataRow.UnknownColumn) .Should().Throw(); } [Fact] public void ShouldResolveDynamicPropertyAccessToColumnsAndNotToOwnProperties() { - dynamic dataRow = new DataRow(new Dictionary { { "ColumnA", Generate.ScalarValue() } }); + dynamic dataRow = new DataRow(new Dictionary { { "ColumnA", Generate.ScalarValue() } }); // "Count" is a property of DataRow, but through a dynamic reference it addresses a column of that name. - Invoking(() => (Object?)dataRow.Count) + Invoking(() => (object?)dataRow.Count) .Should().Throw(); - dynamic rowWithShadowingColumn = new DataRow(new Dictionary { { "Count", 42 } }); + dynamic rowWithShadowingColumn = new DataRow(new Dictionary { { "Count", 42 } }); - ((Object?)rowWithShadowingColumn.Count) + ((object?)rowWithShadowingColumn.Count) .Should().Be(42); } [Fact] public void ShouldResolveDynamicMethodCallsToOwnMembers() { - dynamic dataRow = new DataRow(new Dictionary { { "ColumnA", Generate.ScalarValue() } }); + dynamic dataRow = new DataRow(new Dictionary { { "ColumnA", Generate.ScalarValue() } }); - ((Boolean)dataRow.ContainsKey("ColumnA")) + ((bool)dataRow.ContainsKey("ColumnA")) .Should().BeTrue(); - ((Boolean)dataRow.ContainsKey("ColumnB")) + ((bool)dataRow.ContainsKey("ColumnB")) .Should().BeFalse(); } [Fact] public void ShouldForwardAllMethodCallsToDictionary() { - var exceptions = new HashSet + var exceptions = new HashSet { nameof(IDictionary<,>.TryGetValue) }; @@ -166,7 +166,7 @@ public void ShouldForwardAllMethodCallsToDictionary() fixture.Customize(new AutoNSubstituteCustomization()); fixture.Register(() => new DataTable()); - var dictionary = Substitute.For>(); + var dictionary = Substitute.For>(); var dataRow = new DataRow(dictionary); DecoratorAssertions.AssertDecoratorForwardsAllCalls( @@ -180,7 +180,7 @@ public void ShouldForwardAllMethodCallsToDictionary() [Fact] public void ShouldProvideRowData() { - var dictionary = new Dictionary + var dictionary = new Dictionary { { "ColumnA", Generate.ScalarValue() }, { "ColumnB", Generate.ScalarValue() }, @@ -202,12 +202,12 @@ public void ShouldProvideRowData() [Fact] public void TryGetValue_ShouldForwardCallToDictionary() { - var key = Generate.Single(); + var key = Generate.Single(); var value = Generate.ScalarValue(); - var dictionary = Substitute.For>(); + var dictionary = Substitute.For>(); - dictionary.TryGetValue(key, out Arg.Any()).Returns(a => + dictionary.TryGetValue(key, out Arg.Any()).Returns(a => { a[1] = value; return true; @@ -222,6 +222,6 @@ public void TryGetValue_ShouldForwardCallToDictionary() result .Should().Be(value); - dictionary.Received().TryGetValue(key, out Arg.Any()); + dictionary.Received().TryGetValue(key, out Arg.Any()); } } diff --git a/tests/DbConnectionPlus.UnitTests/Entities/EntityHelperTests.cs b/tests/DbConnectionPlus.UnitTests/Entities/EntityHelperTests.cs index 325aed5..eaed607 100644 --- a/tests/DbConnectionPlus.UnitTests/Entities/EntityHelperTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Entities/EntityHelperTests.cs @@ -13,7 +13,7 @@ public void FindCompatibleConstructor_MatchingPrivateConstructor_ShouldReturnPri { var constructor = EntityHelper.FindCompatibleConstructor( typeof(ItemWithPrivateConstructor), - [("c", typeof(Int64)), ("b", typeof(Int32)), ("a", typeof(Int16))] + [("c", typeof(long)), ("b", typeof(int)), ("a", typeof(short))] ); constructor @@ -22,7 +22,7 @@ public void FindCompatibleConstructor_MatchingPrivateConstructor_ShouldReturnPri constructor .GetParameters() .Select(a => (a.Name, a.ParameterType)) - .Should().BeEquivalentTo([("a", typeof(Int16)), ("b", typeof(Int32)), ("c", typeof(Int64))]); + .Should().BeEquivalentTo([("a", typeof(short)), ("b", typeof(int)), ("c", typeof(long))]); } [Fact] @@ -30,7 +30,7 @@ public void FindCompatibleConstructor_NamesAndTypesMatchWithDifferentOrder_Shoul { var constructor = EntityHelper.FindCompatibleConstructor( typeof(ItemWithConstructor), - [("c", typeof(Int64)), ("b", typeof(Int32)), ("a", typeof(Int16))] + [("c", typeof(long)), ("b", typeof(int)), ("a", typeof(short))] ); constructor @@ -39,14 +39,14 @@ public void FindCompatibleConstructor_NamesAndTypesMatchWithDifferentOrder_Shoul constructor .GetParameters() .Select(a => (a.Name, a.ParameterType)) - .Should().BeEquivalentTo([("a", typeof(Int16)), ("b", typeof(Int32)), ("c", typeof(Int64))]); + .Should().BeEquivalentTo([("a", typeof(short)), ("b", typeof(int)), ("c", typeof(long))]); } [Fact] public void FindCompatibleConstructor_NamesDoNotMatch_TypesMatch_ShouldReturnNull() => EntityHelper.FindCompatibleConstructor( typeof(ItemWithConstructor), - [("d", typeof(Int16)), ("e", typeof(Int32)), ("f", typeof(Int64))] + [("d", typeof(short)), ("e", typeof(int)), ("f", typeof(long))] ) .Should().BeNull(); @@ -55,7 +55,7 @@ public void FindCompatibleConstructor_NamesMatch_TypesAreCompatible_ShouldReturn { var constructor = EntityHelper.FindCompatibleConstructor( typeof(ItemWithConstructor), - [("a", typeof(Int32)), ("b", typeof(Int32)), ("c", typeof(Int32))] + [("a", typeof(int)), ("b", typeof(int)), ("c", typeof(int))] ); constructor @@ -64,14 +64,14 @@ public void FindCompatibleConstructor_NamesMatch_TypesAreCompatible_ShouldReturn constructor .GetParameters() .Select(a => (a.Name, a.ParameterType)) - .Should().BeEquivalentTo([("a", typeof(Int16)), ("b", typeof(Int32)), ("c", typeof(Int64))]); + .Should().BeEquivalentTo([("a", typeof(short)), ("b", typeof(int)), ("c", typeof(long))]); } [Fact] public void FindCompatibleConstructor_NamesMatch_TypesAreIncompatible_ShouldReturnNull() => EntityHelper.FindCompatibleConstructor( typeof(ItemWithConstructor), - [("a", typeof(Int16)), ("b", typeof(Int32)), ("c", typeof(TimeSpan))] + [("a", typeof(short)), ("b", typeof(int)), ("c", typeof(TimeSpan))] ) .Should().BeNull(); @@ -80,7 +80,7 @@ public void FindCompatibleConstructor_NamesMatch_TypesMatch_ShouldReturnConstruc { var constructor = EntityHelper.FindCompatibleConstructor( typeof(ItemWithConstructor), - [("a", typeof(Int16)), ("b", typeof(Int32)), ("c", typeof(Int64))] + [("a", typeof(short)), ("b", typeof(int)), ("c", typeof(long))] ); constructor @@ -89,7 +89,7 @@ public void FindCompatibleConstructor_NamesMatch_TypesMatch_ShouldReturnConstruc constructor .GetParameters() .Select(a => (a.Name, a.ParameterType)) - .Should().BeEquivalentTo([("a", typeof(Int16)), ("b", typeof(Int32)), ("c", typeof(Int64))]); + .Should().BeEquivalentTo([("a", typeof(short)), ("b", typeof(int)), ("c", typeof(long))]); } [Fact] @@ -97,7 +97,7 @@ public void FindCompatibleConstructor_NamesMatchWithDifferentCasing_TypesMatch_S { var constructor = EntityHelper.FindCompatibleConstructor( typeof(ItemWithConstructor), - [("A", typeof(Int16)), ("B", typeof(Int32)), ("C", typeof(Int64))] + [("A", typeof(short)), ("B", typeof(int)), ("C", typeof(long))] ); constructor @@ -106,14 +106,14 @@ public void FindCompatibleConstructor_NamesMatchWithDifferentCasing_TypesMatch_S constructor .GetParameters() .Select(a => a.ParameterType) - .Should().BeEquivalentTo([typeof(Int16), typeof(Int32), typeof(Int64)]); + .Should().BeEquivalentTo([typeof(short), typeof(int), typeof(long)]); } [Fact] public void FindCompatibleConstructor_NoMatchingConstructor_ShouldReturnNull() => EntityHelper.FindCompatibleConstructor( typeof(ItemWithConstructor), - [("a", typeof(Int16)), ("b", typeof(Int32)), ("c", typeof(Int64)), ("d", typeof(String))] + [("a", typeof(short)), ("b", typeof(int)), ("c", typeof(long)), ("d", typeof(string))] ) .Should().BeNull(); @@ -448,8 +448,8 @@ public void GetEntityTypeMetadata_MoreThanOneIdentityProperty_ShouldThrow() => [Fact] public void ShouldGuardAgainstNullArguments() { - (String Name, Type Type)[] constructorParameters = - [("a", typeof(Int16)), ("b", typeof(Int32)), ("c", typeof(Int64))]; + (string Name, Type Type)[] constructorParameters = + [("a", typeof(short)), ("b", typeof(int)), ("c", typeof(long))]; ArgumentNullGuardVerifier.Verify(() => EntityHelper.FindCompatibleConstructor(typeof(ItemWithConstructor), constructorParameters) @@ -534,7 +534,7 @@ public void GetEntityTypeMetadata_ShouldCreateAccessorsForNonPublicAndInitOnlySe /// private sealed class EntityWithThrowingAccessors { - public Int32 Value + public int Value { get => throw new InvalidOperationException("Getter was invoked."); set => throw new InvalidOperationException("Setter was invoked."); @@ -546,12 +546,12 @@ public Int32 Value /// private sealed class EntityWithNonPublicSetter { - public String? Name { get; init; } + public string? Name { get; init; } // The private setter is the point of this entity - it exists to be written through reflection, which // RCS1170 cannot see, so it believes the property should be read-only. #pragma warning disable RCS1170 - public Int32 Value { get; private set; } + public int Value { get; private set; } #pragma warning restore RCS1170 } } diff --git a/tests/DbConnectionPlus.UnitTests/Extensions/DbDataReaderExtensionsTests.cs b/tests/DbConnectionPlus.UnitTests/Extensions/DbDataReaderExtensionsTests.cs index 07e35cf..c156d13 100644 --- a/tests/DbConnectionPlus.UnitTests/Extensions/DbDataReaderExtensionsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Extensions/DbDataReaderExtensionsTests.cs @@ -9,7 +9,7 @@ public class DbDataReaderExtensionsTests : UnitTestsBase [Fact] public void GetFieldNames_ShouldReturnFieldNames() { - String[] fieldNames = ["FieldA", "FieldB", "FieldC"]; + string[] fieldNames = ["FieldA", "FieldB", "FieldC"]; var dataReader = Substitute.For(); @@ -26,7 +26,7 @@ public void GetFieldNames_ShouldReturnFieldNames() [Fact] public void GetFieldTypes_ShouldReturnFieldTypes() { - Type[] fieldTypes = [typeof(Int32), typeof(String), typeof(DateTime)]; + Type[] fieldTypes = [typeof(int), typeof(string), typeof(DateTime)]; var dataReader = Substitute.For(); diff --git a/tests/DbConnectionPlus.UnitTests/Extensions/Int32ExtensionsTests.cs b/tests/DbConnectionPlus.UnitTests/Extensions/Int32ExtensionsTests.cs index a31dc9c..280a0b9 100644 --- a/tests/DbConnectionPlus.UnitTests/Extensions/Int32ExtensionsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Extensions/Int32ExtensionsTests.cs @@ -16,7 +16,7 @@ public class Int32ExtensionsTests : UnitTestsBase [InlineData(23, "23rd")] [InlineData(24, "24th")] [InlineData(25, "25th")] - public void OrdinalizeEnglish_ShouldOrdinalizeNumberInEnglishFormat(Int32 number, String expectedResult) => + public void OrdinalizeEnglish_ShouldOrdinalizeNumberInEnglishFormat(int number, string expectedResult) => number.OrdinalizeEnglish() .Should().Be(expectedResult); } diff --git a/tests/DbConnectionPlus.UnitTests/Extensions/ObjectExtensionsTests.cs b/tests/DbConnectionPlus.UnitTests/Extensions/ObjectExtensionsTests.cs index 582dde3..3763a1e 100644 --- a/tests/DbConnectionPlus.UnitTests/Extensions/ObjectExtensionsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Extensions/ObjectExtensionsTests.cs @@ -18,23 +18,23 @@ public class ObjectExtensionsTests : UnitTestsBase [Fact] public void ToDebugString_ShouldRenderSequencesElementByElement() { - new List { "A", "B" }.ToDebugString() + new List { "A", "B" }.ToDebugString() .Should().Be("'[A,B]' (System.Collections.Generic.List`1[System.String])"); - new Object?[] { 1, null, "A", true }.ToDebugString() + new object?[] { 1, null, "A", true }.ToDebugString() .Should().Be("'[1,{null},A,True]' (System.Object[])"); - new Int32[][] { [1, 2], [3] }.ToDebugString() + new int[][] { [1, 2], [3] }.ToDebugString() .Should().Be("'[[1,2],[3]]' (System.Int32[][])"); - Array.Empty().ToDebugString() + Array.Empty().ToDebugString() .Should().Be("'[]' (System.Int32[])"); } [Fact] public void ToDebugString_ShouldTruncateSelfReferencingSequencesInsteadOfRecursingForever() { - var values = new List { 1 }; + var values = new List { 1 }; values.Add(values); @@ -51,7 +51,7 @@ public void ToDebugString_ShouldTruncateSelfReferencingSequencesInsteadOfRecursi public void ToDebugString_ShouldReturnStringRepresentationOfValue() { #pragma warning disable RCS1202 - (null as Object).ToDebugString() + (null as object).ToDebugString() .Should().Be("{null}"); #pragma warning restore RCS1202 @@ -61,10 +61,10 @@ public void ToDebugString_ShouldReturnStringRepresentationOfValue() true.ToDebugString() .Should().Be("'True' (System.Boolean)"); - ((Byte)123).ToDebugString() + ((byte)123).ToDebugString() .Should().Be("'123' (System.Byte)"); - new Byte[] { 1, 2, 3 }.ToDebugString() + new byte[] { 1, 2, 3 }.ToDebugString() .Should().Be("'AQID' (System.Byte[])"); 'X'.ToDebugString() @@ -88,22 +88,22 @@ public void ToDebugString_ShouldReturnStringRepresentationOfValue() new Guid("889a8be0-f0ff-4555-86d8-8490434b7def").ToDebugString() .Should().Be("'889a8be0-f0ff-4555-86d8-8490434b7def' (System.Guid)"); - ((Int16)123).ToDebugString() + ((short)123).ToDebugString() .Should().Be("'123' (System.Int16)"); 123.ToDebugString() .Should().Be("'123' (System.Int32)"); - ((Int64)123).ToDebugString() + ((long)123).ToDebugString() .Should().Be("'123' (System.Int64)"); ((IntPtr)123).ToDebugString() .Should().Be("'123' (System.IntPtr)"); - ((SByte)123).ToDebugString() + ((sbyte)123).ToDebugString() .Should().Be("'123' (System.SByte)"); - ((Single)123.45).ToDebugString() + ((float)123.45).ToDebugString() .Should().Be("'123.449997' (System.Single)"); "A String".ToDebugString() @@ -112,24 +112,24 @@ public void ToDebugString_ShouldReturnStringRepresentationOfValue() new TimeSpan(1, 2, 3, 4).ToDebugString() .Should().Be("'1.02:03:04' (System.TimeSpan)"); - ((UInt16)123).ToDebugString() + ((ushort)123).ToDebugString() .Should().Be("'123' (System.UInt16)"); - ((UInt32)123).ToDebugString() + ((uint)123).ToDebugString() .Should().Be("'123' (System.UInt32)"); - ((UInt64)123).ToDebugString() + ((ulong)123).ToDebugString() .Should().Be("'123' (System.UInt64)"); ((UIntPtr)123).ToDebugString() .Should().Be("'123' (System.UIntPtr)"); #pragma warning disable CA1861 // Avoid constant arrays as arguments - new Int32[] { 1, 2, 3 }.ToDebugString() + new int[] { 1, 2, 3 }.ToDebugString() .Should().Be("'[1,2,3]' (System.Int32[])"); #pragma warning restore CA1861 // Avoid constant arrays as arguments - new Object().ToDebugString() + new object().ToDebugString() .Should().Be("'System.Object' (System.Object)"); new EntityWithEnumStoredAsString { Enum = TestEnum.Value3, Id = 1 }.ToDebugString() @@ -139,10 +139,10 @@ public void ToDebugString_ShouldReturnStringRepresentationOfValue() ); } - private sealed class Item(String id) + private sealed class Item(string id) { /// - public override String ToString() => + public override string ToString() => $"Item {id}"; } } diff --git a/tests/DbConnectionPlus.UnitTests/Extensions/TypeExtensionsTests.cs b/tests/DbConnectionPlus.UnitTests/Extensions/TypeExtensionsTests.cs index ce9d29e..66c5971 100644 --- a/tests/DbConnectionPlus.UnitTests/Extensions/TypeExtensionsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Extensions/TypeExtensionsTests.cs @@ -8,67 +8,67 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.Extensions; public class TypeExtensionsTests : UnitTestsBase { [Theory] - [InlineData(typeof(Boolean), true)] - [InlineData(typeof(Boolean?), true)] - [InlineData(typeof(Byte), true)] - [InlineData(typeof(Byte?), true)] - [InlineData(typeof(Char), true)] - [InlineData(typeof(Char?), true)] + [InlineData(typeof(bool), true)] + [InlineData(typeof(bool?), true)] + [InlineData(typeof(byte), true)] + [InlineData(typeof(byte?), true)] + [InlineData(typeof(char), true)] + [InlineData(typeof(char?), true)] [InlineData(typeof(DateOnly), true)] [InlineData(typeof(DateOnly?), true)] [InlineData(typeof(DateTime), true)] [InlineData(typeof(DateTime?), true)] [InlineData(typeof(DateTimeOffset), true)] [InlineData(typeof(DateTimeOffset?), true)] - [InlineData(typeof(Decimal), true)] - [InlineData(typeof(Decimal?), true)] - [InlineData(typeof(Double), true)] - [InlineData(typeof(Double?), true)] + [InlineData(typeof(decimal), true)] + [InlineData(typeof(decimal?), true)] + [InlineData(typeof(double), true)] + [InlineData(typeof(double?), true)] [InlineData(typeof(Guid), true)] [InlineData(typeof(Guid?), true)] - [InlineData(typeof(Int16), true)] - [InlineData(typeof(Int16?), true)] - [InlineData(typeof(Int32), true)] - [InlineData(typeof(Int32?), true)] - [InlineData(typeof(Int64), true)] - [InlineData(typeof(Int64?), true)] + [InlineData(typeof(short), true)] + [InlineData(typeof(short?), true)] + [InlineData(typeof(int), true)] + [InlineData(typeof(int?), true)] + [InlineData(typeof(long), true)] + [InlineData(typeof(long?), true)] [InlineData(typeof(IntPtr), true)] [InlineData(typeof(IntPtr?), true)] - [InlineData(typeof(SByte), true)] - [InlineData(typeof(SByte?), true)] - [InlineData(typeof(Single), true)] - [InlineData(typeof(Single?), true)] - [InlineData(typeof(String), true)] + [InlineData(typeof(sbyte), true)] + [InlineData(typeof(sbyte?), true)] + [InlineData(typeof(float), true)] + [InlineData(typeof(float?), true)] + [InlineData(typeof(string), true)] [InlineData(typeof(TimeOnly), true)] [InlineData(typeof(TimeOnly?), true)] [InlineData(typeof(TimeSpan), true)] [InlineData(typeof(TimeSpan?), true)] - [InlineData(typeof(UInt16), true)] - [InlineData(typeof(UInt16?), true)] - [InlineData(typeof(UInt32), true)] - [InlineData(typeof(UInt32?), true)] - [InlineData(typeof(UInt64), true)] - [InlineData(typeof(UInt64?), true)] + [InlineData(typeof(ushort), true)] + [InlineData(typeof(ushort?), true)] + [InlineData(typeof(uint), true)] + [InlineData(typeof(uint?), true)] + [InlineData(typeof(ulong), true)] + [InlineData(typeof(ulong?), true)] [InlineData(typeof(UIntPtr), true)] [InlineData(typeof(UIntPtr?), true)] [InlineData(typeof(Entity), false)] [InlineData(typeof(TestEnum), false)] public void IsBuiltInTypeOrNullableBuiltInType_ShouldDetermineWhetherTypeIsBuiltInTypeOrNullableBuiltInType( Type type, - Boolean expectedResult + bool expectedResult ) => type.IsBuiltInTypeOrNullableBuiltInType() .Should().Be(expectedResult); [Theory] - [InlineData(typeof(Char), true)] - [InlineData(typeof(Char?), true)] - [InlineData(typeof(String), false)] + [InlineData(typeof(char), true)] + [InlineData(typeof(char?), true)] + [InlineData(typeof(string), false)] [InlineData(typeof(DateTime), false)] [InlineData(typeof(Entity), false)] public void IsCharOrNullableCharType_ShouldDetermineWhetherTypeIsCharOrNullableCharType( Type type, - Boolean expectedResult + bool expectedResult ) => type.IsCharOrNullableCharType() .Should().Be(expectedResult); @@ -78,48 +78,48 @@ Boolean expectedResult [InlineData(typeof(TestEnum?), true)] [InlineData(typeof(ConsoleColor), true)] [InlineData(typeof(ConsoleColor?), true)] - [InlineData(typeof(String), false)] + [InlineData(typeof(string), false)] [InlineData(typeof(DateTime), false)] [InlineData(typeof(Entity), false)] public void IsEnumOrNullableEnumType_ShouldDetermineWhetherTypeIsEnumTypeOrNullableEnumType( Type type, - Boolean expectedResult + bool expectedResult ) => type.IsEnumOrNullableEnumType() .Should().Be(expectedResult); [Theory] - [InlineData(typeof(Int32?), true)] + [InlineData(typeof(int?), true)] [InlineData(typeof(DateTime?), true)] - [InlineData(typeof(Object), true)] + [InlineData(typeof(object), true)] [InlineData(typeof(Entity), true)] - [InlineData(typeof(Int32[]), true)] - [InlineData(typeof(String[]), true)] - [InlineData(typeof(Int32), false)] + [InlineData(typeof(int[]), true)] + [InlineData(typeof(string[]), true)] + [InlineData(typeof(int), false)] [InlineData(typeof(DateTime), false)] public void IsReferenceTypeOrNullableType_ShouldDetermineWhetherTypeIsReferenceTypeOrNullableType( Type type, - Boolean expectedResult + bool expectedResult ) => type.IsReferenceTypeOrNullableType() .Should().Be(expectedResult); [Theory] - [InlineData(typeof(ValueTuple), true)] - [InlineData(typeof(ValueTuple), true)] - [InlineData(typeof(ValueTuple), true)] - [InlineData(typeof(ValueTuple), true)] - [InlineData(typeof(ValueTuple), true)] - [InlineData(typeof(ValueTuple), true)] - [InlineData(typeof(ValueTuple), true)] - [InlineData(typeof(ValueTuple), true)] + [InlineData(typeof(ValueTuple), true)] + [InlineData(typeof(ValueTuple), true)] + [InlineData(typeof(ValueTuple), true)] + [InlineData(typeof(ValueTuple), true)] + [InlineData(typeof(ValueTuple), true)] + [InlineData(typeof(ValueTuple), true)] + [InlineData(typeof(ValueTuple), true)] + [InlineData(typeof(ValueTuple), true)] [InlineData(typeof(DateTime), false)] [InlineData(typeof(Entity), false)] - [InlineData(typeof(Tuple), false)] - [InlineData(typeof(Tuple), false)] + [InlineData(typeof(Tuple), false)] + [InlineData(typeof(Tuple), false)] public void IsValueTupleType_ShouldDetermineWhetherTypeIsValueTupleType( Type type, - Boolean expectedResult + bool expectedResult ) => type.IsValueTupleType() .Should().Be(expectedResult); @@ -128,9 +128,9 @@ Boolean expectedResult public void ShouldGuardAgainstNullArguments() { ArgumentNullGuardVerifier.Verify(() => TypeExtensions.IsBuiltInTypeOrNullableBuiltInType(typeof(DateTime))); - ArgumentNullGuardVerifier.Verify(() => TypeExtensions.IsCharOrNullableCharType(typeof(Char))); + ArgumentNullGuardVerifier.Verify(() => TypeExtensions.IsCharOrNullableCharType(typeof(char))); ArgumentNullGuardVerifier.Verify(() => TypeExtensions.IsEnumOrNullableEnumType(typeof(TestEnum))); ArgumentNullGuardVerifier.Verify(() => TypeExtensions.IsReferenceTypeOrNullableType(typeof(Entity))); - ArgumentNullGuardVerifier.Verify(() => TypeExtensions.IsValueTupleType(typeof(ValueTuple))); + ArgumentNullGuardVerifier.Verify(() => TypeExtensions.IsValueTupleType(typeof(ValueTuple))); } } diff --git a/tests/DbConnectionPlus.UnitTests/Helpers/NameHelperTests.cs b/tests/DbConnectionPlus.UnitTests/Helpers/NameHelperTests.cs index b537fe9..55e8846 100644 --- a/tests/DbConnectionPlus.UnitTests/Helpers/NameHelperTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Helpers/NameHelperTests.cs @@ -19,9 +19,9 @@ public class NameHelperTests : UnitTestsBase [InlineData("..........1234567890", 10, "1234567890")] [InlineData(".....12345.....67890", 10, "1234567890")] public void CreateNameFromCallerArgumentExpression_ShouldCreateName( - String expression, - Int32 maximumLength, - String expectedName + string expression, + int maximumLength, + string expectedName ) => NameHelper.CreateNameFromCallerArgumentExpression(expression, maximumLength) .Should().Be(expectedName); diff --git a/tests/DbConnectionPlus.UnitTests/Materializers/DataRowMaterializerTests.cs b/tests/DbConnectionPlus.UnitTests/Materializers/DataRowMaterializerTests.cs index 898d9b2..facfb44 100644 --- a/tests/DbConnectionPlus.UnitTests/Materializers/DataRowMaterializerTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Materializers/DataRowMaterializerTests.cs @@ -20,10 +20,10 @@ public void Materialize_ReturnsDataRowWithAllColumnsAndValues() dataReader.GetName(2).Returns("ColumnC"); dataReader - .GetValues(Arg.Any()) + .GetValues(Arg.Any()) .Returns(callInfo => { - var array = callInfo.Arg(); + var array = callInfo.Arg(); array[0] = value1; array[1] = value2; array[2] = value3; diff --git a/tests/DbConnectionPlus.UnitTests/Materializers/EntityMaterializerFactoryTests.cs b/tests/DbConnectionPlus.UnitTests/Materializers/EntityMaterializerFactoryTests.cs index c57443d..c69c1ad 100644 --- a/tests/DbConnectionPlus.UnitTests/Materializers/EntityMaterializerFactoryTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Materializers/EntityMaterializerFactoryTests.cs @@ -18,8 +18,8 @@ public void GetMaterializer_DataReaderFieldHasNoName_ShouldThrow() dataReader.FieldCount.Returns(1); - dataReader.GetFieldType(0).Returns(typeof(String)); - dataReader.GetName(0).Returns(String.Empty); + dataReader.GetFieldType(0).Returns(typeof(string)); + dataReader.GetName(0).Returns(string.Empty); Invoking(() => EntityMaterializerFactory.GetMaterializer(dataReader)) .Should().Throw() @@ -43,7 +43,7 @@ public void GetMaterializer_DataReaderFieldTypeNotCompatibleWithEntityPropertyTy .Should().Throw() .WithMessage( $"The data type {typeof(Guid)} of the column 'CharValue' returned by the SQL statement is not " + - $"compatible with the property type {typeof(Char)} of the corresponding property of the type " + + $"compatible with the property type {typeof(char)} of the corresponding property of the type " + $"{typeof(Entity)}.*" ); } @@ -68,10 +68,10 @@ public void GetMaterializer_NoFieldMatchesAWritableProperty_ShouldThrow() dataReader.FieldCount.Returns(2); dataReader.GetName(0).Returns("NotAPropertyOfEntity"); - dataReader.GetFieldType(0).Returns(typeof(String)); + dataReader.GetFieldType(0).Returns(typeof(string)); dataReader.GetName(1).Returns("AlsoNotAPropertyOfEntity"); - dataReader.GetFieldType(1).Returns(typeof(Int32)); + dataReader.GetFieldType(1).Returns(typeof(int)); Invoking(() => EntityMaterializerFactory.GetMaterializer(dataReader)) .Should().Throw() @@ -89,10 +89,10 @@ public void GetMaterializer_SomeFieldsMatchAWritableProperty_ShouldNotThrow() dataReader.FieldCount.Returns(2); dataReader.GetName(0).Returns("CharValue"); - dataReader.GetFieldType(0).Returns(typeof(String)); + dataReader.GetFieldType(0).Returns(typeof(string)); dataReader.GetName(1).Returns("NotAPropertyOfEntity"); - dataReader.GetFieldType(1).Returns(typeof(String)); + dataReader.GetFieldType(1).Returns(typeof(string)); Invoking(() => EntityMaterializerFactory.GetMaterializer(dataReader)) .Should().NotThrow(); @@ -127,9 +127,9 @@ public void dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("CharValue"); - dataReader.GetFieldType(0).Returns(typeof(String)); + dataReader.GetFieldType(0).Returns(typeof(string)); dataReader.IsDBNull(0).Returns(false); - dataReader.GetString(0).Returns(String.Empty); + dataReader.GetString(0).Returns(string.Empty); var materializer = EntityMaterializerFactory.GetMaterializer(dataReader); @@ -137,12 +137,12 @@ public void .Should().Throw() .WithMessage( "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(Char)} of the corresponding property of the type " + + $"to the type {typeof(char)} of the corresponding property of the type " + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException() .WithMessage( - $"Could not convert the string '' to the type {typeof(Char)}. The string must be exactly one " + + $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly one " + "character long." ); @@ -152,12 +152,12 @@ public void .Should().Throw() .WithMessage( "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(Char)} of the corresponding property of the type " + + $"to the type {typeof(char)} of the corresponding property of the type " + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be exactly " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + "one character long." ); } @@ -170,10 +170,10 @@ public void dataReader.FieldCount.Returns(1); - var character = Generate.Single(); + var character = Generate.Single(); dataReader.GetName(0).Returns("CharValue"); - dataReader.GetFieldType(0).Returns(typeof(String)); + dataReader.GetFieldType(0).Returns(typeof(string)); dataReader.IsDBNull(0).Returns(false); dataReader.GetString(0).Returns(character.ToString()); @@ -227,7 +227,7 @@ public void Materializer_DataReaderFieldNameMatchesEntityPropertyCaseInsensitive dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("id"); // lower-case - dataReader.GetFieldType(0).Returns(typeof(Int64)); + dataReader.GetFieldType(0).Returns(typeof(long)); dataReader.IsDBNull(0).Returns(false); dataReader.GetInt64(0).Returns(789); @@ -250,14 +250,14 @@ public void Materializer_DataReaderHasCompatibleFieldTypes_ShouldConvertValues() dataReader.FieldCount.Returns(2); dataReader.GetName(0).Returns("Id"); - dataReader.GetFieldType(0).Returns(typeof(String)); // EntityWithEnumStoredAsInteger.Id is of type Int64. + dataReader.GetFieldType(0).Returns(typeof(string)); // EntityWithEnumStoredAsInteger.Id is of type Int64. dataReader.IsDBNull(0).Returns(false); dataReader.GetString(0).Returns(entityId.ToString()); dataReader.GetName(1).Returns("Enum"); - dataReader.GetFieldType(1).Returns(typeof(Decimal)); // EntityWithEnumStoredAsInteger.Enum is of type TestEnum. + dataReader.GetFieldType(1).Returns(typeof(decimal)); // EntityWithEnumStoredAsInteger.Enum is of type TestEnum. dataReader.IsDBNull(1).Returns(false); - dataReader.GetDecimal(1).Returns((Decimal)enumValue); + dataReader.GetDecimal(1).Returns((decimal)enumValue); var materializer = EntityMaterializerFactory.GetMaterializer(dataReader); @@ -276,21 +276,21 @@ public void Materializer_EntityHasNoCorrespondingPropertyForDataReaderField_Shou var dataReader = Substitute.For(); var id = Generate.Id(); - var value = Generate.Single(); + var value = Generate.Single(); dataReader.FieldCount.Returns(3); - dataReader.GetFieldType(0).Returns(typeof(Int64)); + dataReader.GetFieldType(0).Returns(typeof(long)); dataReader.GetName(0).Returns("Id"); dataReader.IsDBNull(0).Returns(false); dataReader.GetInt64(0).Returns(id); - dataReader.GetFieldType(1).Returns(typeof(Int32)); + dataReader.GetFieldType(1).Returns(typeof(int)); dataReader.GetName(1).Returns("Int32Value"); dataReader.IsDBNull(1).Returns(false); dataReader.GetInt32(1).Returns(value); - dataReader.GetFieldType(2).Returns(typeof(Int32)); + dataReader.GetFieldType(2).Returns(typeof(int)); dataReader.GetName(2).Returns("NonExistent"); dataReader.IsDBNull(2).Returns(false); dataReader.GetInt64(2).Returns(Generate.SmallNumber()); @@ -319,9 +319,9 @@ public void Materializer_EnumEntityProperty_DataReaderFieldContainsInteger_Shoul dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("Enum"); - dataReader.GetFieldType(0).Returns(typeof(Int32)); + dataReader.GetFieldType(0).Returns(typeof(int)); dataReader.IsDBNull(0).Returns(false); - dataReader.GetInt32(0).Returns((Int32)enumValue); + dataReader.GetInt32(0).Returns((int)enumValue); var materializer = EntityMaterializerFactory.GetMaterializer(dataReader); @@ -340,7 +340,7 @@ public void dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("Enum"); - dataReader.GetFieldType(0).Returns(typeof(Int32)); + dataReader.GetFieldType(0).Returns(typeof(int)); dataReader.IsDBNull(0).Returns(false); dataReader.GetInt32(0).Returns(999); @@ -355,7 +355,7 @@ public void ) .WithInnerException() .WithMessage( - $"Could not convert the value '999' ({typeof(Int32)}) to an enum member of the type " + + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); } @@ -370,7 +370,7 @@ public void Materializer_EnumEntityProperty_DataReaderFieldContainsString_Should dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("Enum"); - dataReader.GetFieldType(0).Returns(typeof(String)); + dataReader.GetFieldType(0).Returns(typeof(string)); dataReader.IsDBNull(0).Returns(false); dataReader.GetString(0).Returns(enumValue.ToString()); @@ -390,7 +390,7 @@ public void Materializer_EnumEntityProperty_DataReaderFieldContainsStringNotMatc dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("Enum"); - dataReader.GetFieldType(0).Returns(typeof(String)); + dataReader.GetFieldType(0).Returns(typeof(string)); dataReader.IsDBNull(0).Returns(false); dataReader.GetString(0).Returns("NonExistent"); @@ -421,48 +421,48 @@ public void Materializer_Mapping_Attributes_ShouldUseAttributesMapping() var ordinal = 0; dataReader.GetName(ordinal).Returns("Computed"); - dataReader.GetFieldType(ordinal).Returns(typeof(Int32)); + dataReader.GetFieldType(ordinal).Returns(typeof(int)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt32(ordinal).Returns(entity.Computed_); ordinal++; dataReader.GetName(ordinal).Returns("ConcurrencyToken"); - dataReader.GetFieldType(ordinal).Returns(typeof(Byte[])); + dataReader.GetFieldType(ordinal).Returns(typeof(byte[])); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetValue(ordinal).Returns(entity.ConcurrencyToken_); ordinal++; dataReader.GetName(ordinal).Returns("Identity"); - dataReader.GetFieldType(ordinal).Returns(typeof(Int32)); + dataReader.GetFieldType(ordinal).Returns(typeof(int)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt32(ordinal).Returns(entity.Identity_); ordinal++; dataReader.GetName(ordinal).Returns("Key1"); - dataReader.GetFieldType(ordinal).Returns(typeof(Int64)); + dataReader.GetFieldType(ordinal).Returns(typeof(long)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt64(ordinal).Returns(entity.Key1_); ordinal++; dataReader.GetName(ordinal).Returns("Key2"); - dataReader.GetFieldType(ordinal).Returns(typeof(Int64)); + dataReader.GetFieldType(ordinal).Returns(typeof(long)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt64(ordinal).Returns(entity.Key2_); ordinal++; dataReader.GetName(ordinal).Returns("Value"); - dataReader.GetFieldType(ordinal).Returns(typeof(Int32)); + dataReader.GetFieldType(ordinal).Returns(typeof(int)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt32(ordinal).Returns(entity.Value_); ordinal++; var notMappedColumnOrdinal = ordinal; dataReader.GetName(notMappedColumnOrdinal).Returns("NotMapped"); - dataReader.GetFieldType(notMappedColumnOrdinal).Returns(typeof(String)); + dataReader.GetFieldType(notMappedColumnOrdinal).Returns(typeof(string)); ordinal++; dataReader.GetName(ordinal).Returns("RowVersion"); - dataReader.GetFieldType(ordinal).Returns(typeof(Byte[])); + dataReader.GetFieldType(ordinal).Returns(typeof(byte[])); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetValue(ordinal).Returns(entity.RowVersion_); @@ -511,48 +511,48 @@ public void Materializer_Mapping_FluentApi_ShouldUseFluentApiMapping() var ordinal = 0; dataReader.GetName(ordinal).Returns("Computed"); - dataReader.GetFieldType(ordinal).Returns(typeof(Int32)); + dataReader.GetFieldType(ordinal).Returns(typeof(int)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt32(ordinal).Returns(entity.Computed_); ordinal++; dataReader.GetName(ordinal).Returns("ConcurrencyToken"); - dataReader.GetFieldType(ordinal).Returns(typeof(Byte[])); + dataReader.GetFieldType(ordinal).Returns(typeof(byte[])); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetValue(ordinal).Returns(entity.ConcurrencyToken_); ordinal++; dataReader.GetName(ordinal).Returns("Identity"); - dataReader.GetFieldType(ordinal).Returns(typeof(Int32)); + dataReader.GetFieldType(ordinal).Returns(typeof(int)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt32(ordinal).Returns(entity.Identity_); ordinal++; dataReader.GetName(ordinal).Returns("Key1"); - dataReader.GetFieldType(ordinal).Returns(typeof(Int64)); + dataReader.GetFieldType(ordinal).Returns(typeof(long)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt64(ordinal).Returns(entity.Key1_); ordinal++; dataReader.GetName(ordinal).Returns("Key2"); - dataReader.GetFieldType(ordinal).Returns(typeof(Int64)); + dataReader.GetFieldType(ordinal).Returns(typeof(long)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt64(ordinal).Returns(entity.Key2_); ordinal++; dataReader.GetName(ordinal).Returns("Value"); - dataReader.GetFieldType(ordinal).Returns(typeof(Int32)); + dataReader.GetFieldType(ordinal).Returns(typeof(int)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt32(ordinal).Returns(entity.Value_); ordinal++; var notMappedColumnOrdinal = ordinal; dataReader.GetName(notMappedColumnOrdinal).Returns("NotMapped"); - dataReader.GetFieldType(notMappedColumnOrdinal).Returns(typeof(String)); + dataReader.GetFieldType(notMappedColumnOrdinal).Returns(typeof(string)); ordinal++; dataReader.GetName(ordinal).Returns("RowVersion"); - dataReader.GetFieldType(ordinal).Returns(typeof(Byte[])); + dataReader.GetFieldType(ordinal).Returns(typeof(byte[])); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetValue(ordinal).Returns(entity.RowVersion_); @@ -599,19 +599,19 @@ public void Materializer_Mapping_NoMapping_ShouldUseEntityTypeNameAndPropertyNam var ordinal = 0; dataReader.GetName(ordinal).Returns("Key1"); - dataReader.GetFieldType(ordinal).Returns(typeof(Int64)); + dataReader.GetFieldType(ordinal).Returns(typeof(long)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt64(ordinal).Returns(entity.Key1); ordinal++; dataReader.GetName(ordinal).Returns("Key2"); - dataReader.GetFieldType(ordinal).Returns(typeof(Int64)); + dataReader.GetFieldType(ordinal).Returns(typeof(long)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt64(ordinal).Returns(entity.Key2); ordinal++; dataReader.GetName(ordinal).Returns("Value"); - dataReader.GetFieldType(ordinal).Returns(typeof(Int32)); + dataReader.GetFieldType(ordinal).Returns(typeof(int)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt32(ordinal).Returns(entity.Value); @@ -637,7 +637,7 @@ public void Materializer_NoCompatibleConstructor_NoParameterlessConstructor_Shou dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("NonExistent"); - dataReader.GetFieldType(0).Returns(typeof(Int64)); + dataReader.GetFieldType(0).Returns(typeof(long)); Invoking(() => EntityMaterializerFactory.GetMaterializer(dataReader)) .Should().Throw() @@ -696,7 +696,7 @@ public void dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("Id"); - dataReader.GetFieldType(0).Returns(typeof(Int64)); + dataReader.GetFieldType(0).Returns(typeof(long)); dataReader.IsDBNull(0).Returns(true); var materializer = EntityMaterializerFactory.GetMaterializer(dataReader); @@ -717,7 +717,7 @@ public void Materializer_NullableEntityProperty_DataReaderFieldContainsNull_Shou dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("NullableBooleanValue"); - dataReader.GetFieldType(0).Returns(typeof(Boolean)); + dataReader.GetFieldType(0).Returns(typeof(bool)); dataReader.IsDBNull(0).Returns(true); dataReader.GetBoolean(0).Throws(new SqlNullValueException()); @@ -760,7 +760,7 @@ public void Materializer_ShouldMaterializeDateTimeOffsetValue() var ordinal = 0; dataReader.GetName(ordinal).Returns("Id"); - dataReader.GetFieldType(ordinal).Returns(typeof(Int64)); + dataReader.GetFieldType(ordinal).Returns(typeof(long)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt64(ordinal).Returns(entity.Id); @@ -810,20 +810,20 @@ public void ReflectionMaterializer_Mapping_Attributes_ShouldUseAttributesMapping var ordinal = 0; dataReader.GetName(ordinal).Returns("Key1"); - dataReader.GetFieldType(ordinal).Returns(typeof(Int64)); + dataReader.GetFieldType(ordinal).Returns(typeof(long)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt64(ordinal).Returns(entity.Key1_); ordinal++; dataReader.GetName(ordinal).Returns("Value"); - dataReader.GetFieldType(ordinal).Returns(typeof(Int32)); + dataReader.GetFieldType(ordinal).Returns(typeof(int)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt32(ordinal).Returns(entity.Value_); ordinal++; var notMappedColumnOrdinal = ordinal; dataReader.GetName(notMappedColumnOrdinal).Returns("NotMapped"); - dataReader.GetFieldType(notMappedColumnOrdinal).Returns(typeof(String)); + dataReader.GetFieldType(notMappedColumnOrdinal).Returns(typeof(string)); var materializer = GetReflectionMaterializer(dataReader); @@ -850,7 +850,7 @@ public void ReflectionMaterializer_DataReaderFieldNameMatchesEntityPropertyCaseI dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("id"); // lower-case - dataReader.GetFieldType(0).Returns(typeof(Int64)); + dataReader.GetFieldType(0).Returns(typeof(long)); dataReader.IsDBNull(0).Returns(false); dataReader.GetInt64(0).Returns(789); @@ -871,14 +871,14 @@ public void ReflectionMaterializer_DataReaderHasCompatibleFieldTypes_ShouldConve dataReader.FieldCount.Returns(2); dataReader.GetName(0).Returns("Id"); - dataReader.GetFieldType(0).Returns(typeof(String)); // EntityWithEnumStoredAsInteger.Id is of type Int64. + dataReader.GetFieldType(0).Returns(typeof(string)); // EntityWithEnumStoredAsInteger.Id is of type Int64. dataReader.IsDBNull(0).Returns(false); dataReader.GetString(0).Returns(entityId.ToString()); dataReader.GetName(1).Returns("Enum"); - dataReader.GetFieldType(1).Returns(typeof(Decimal)); // EntityWithEnumStoredAsInteger.Enum is of type TestEnum. + dataReader.GetFieldType(1).Returns(typeof(decimal)); // EntityWithEnumStoredAsInteger.Enum is of type TestEnum. dataReader.IsDBNull(1).Returns(false); - dataReader.GetDecimal(1).Returns((Decimal)enumValue); + dataReader.GetDecimal(1).Returns((decimal)enumValue); var materializer = GetReflectionMaterializer(dataReader); @@ -899,7 +899,7 @@ public void ReflectionMaterializer_DataReaderFieldValueCannotBeConverted_ShouldT dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("CharValue"); - dataReader.GetFieldType(0).Returns(typeof(String)); + dataReader.GetFieldType(0).Returns(typeof(string)); dataReader.IsDBNull(0).Returns(false); dataReader.GetString(0).Returns("ab"); @@ -909,12 +909,12 @@ public void ReflectionMaterializer_DataReaderFieldValueCannotBeConverted_ShouldT .Should().Throw() .WithMessage( "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(Char)} of the corresponding property of the type " + + $"to the type {typeof(char)} of the corresponding property of the type " + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be exactly " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + "one character long." ); } @@ -927,7 +927,7 @@ public void ReflectionMaterializer_NonNullableEntityProperty_DataReaderFieldCont dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("Id"); - dataReader.GetFieldType(0).Returns(typeof(Int64)); + dataReader.GetFieldType(0).Returns(typeof(long)); dataReader.IsDBNull(0).Returns(true); var materializer = GetReflectionMaterializer(dataReader); @@ -948,7 +948,7 @@ public void ReflectionMaterializer_NullableEntityProperty_DataReaderFieldContain dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("NullableBooleanValue"); - dataReader.GetFieldType(0).Returns(typeof(Boolean)); + dataReader.GetFieldType(0).Returns(typeof(bool)); dataReader.IsDBNull(0).Returns(true); dataReader.GetBoolean(0).Throws(new SqlNullValueException()); @@ -972,7 +972,7 @@ public void ReflectionMaterializer_ShouldMaterializeDateTimeOffsetValue() var ordinal = 0; dataReader.GetName(ordinal).Returns("Id"); - dataReader.GetFieldType(ordinal).Returns(typeof(Int64)); + dataReader.GetFieldType(ordinal).Returns(typeof(long)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt64(ordinal).Returns(entity.Id); @@ -1028,7 +1028,7 @@ public void ReflectionMaterializer_CompatiblePrivateConstructor_ShouldUsePrivate public void ReflectionMaterializer_ConstructorParametersInADifferentOrderThanTheFields_ShouldMaterialize() { var enumValue = Generate.Single(); - var name = Generate.Single(); + var name = Generate.Single(); var id = Generate.Id(); // Item's constructor is (Id, Name, Enum); the result set deliberately returns the columns in another order. @@ -1037,17 +1037,17 @@ public void ReflectionMaterializer_ConstructorParametersInADifferentOrderThanThe dataReader.FieldCount.Returns(3); dataReader.GetName(0).Returns("Name"); - dataReader.GetFieldType(0).Returns(typeof(String)); + dataReader.GetFieldType(0).Returns(typeof(string)); dataReader.IsDBNull(0).Returns(false); dataReader.GetString(0).Returns(name); dataReader.GetName(1).Returns("Enum"); - dataReader.GetFieldType(1).Returns(typeof(Int32)); // Item.Enum is of type TestEnum. + dataReader.GetFieldType(1).Returns(typeof(int)); // Item.Enum is of type TestEnum. dataReader.IsDBNull(1).Returns(false); - dataReader.GetInt32(1).Returns((Int32)enumValue); + dataReader.GetInt32(1).Returns((int)enumValue); dataReader.GetName(2).Returns("Id"); - dataReader.GetFieldType(2).Returns(typeof(Int64)); + dataReader.GetFieldType(2).Returns(typeof(long)); dataReader.IsDBNull(2).Returns(false); dataReader.GetInt64(2).Returns(id); @@ -1170,17 +1170,17 @@ private static DbDataReader CreateItemDataReader() dataReader.FieldCount.Returns(3); dataReader.GetName(0).Returns("Id"); - dataReader.GetFieldType(0).Returns(typeof(Int64)); + dataReader.GetFieldType(0).Returns(typeof(long)); dataReader.IsDBNull(0).Returns(false); dataReader.GetInt64(0).Returns(Generate.Id()); dataReader.GetName(1).Returns("Name"); - dataReader.GetFieldType(1).Returns(typeof(String)); + dataReader.GetFieldType(1).Returns(typeof(string)); dataReader.IsDBNull(1).Returns(false); - dataReader.GetString(1).Returns(Generate.Single()); + dataReader.GetString(1).Returns(Generate.Single()); dataReader.GetName(2).Returns("Enum"); - dataReader.GetFieldType(2).Returns(typeof(String)); // Item.Enum is of type TestEnum. + dataReader.GetFieldType(2).Returns(typeof(string)); // Item.Enum is of type TestEnum. dataReader.IsDBNull(2).Returns(false); dataReader.GetString(2).Returns(Generate.Single().ToString()); diff --git a/tests/DbConnectionPlus.UnitTests/Materializers/MaterializerFactoryHelperTests.cs b/tests/DbConnectionPlus.UnitTests/Materializers/MaterializerFactoryHelperTests.cs index 4ff45e8..0ce6f2b 100644 --- a/tests/DbConnectionPlus.UnitTests/Materializers/MaterializerFactoryHelperTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Materializers/MaterializerFactoryHelperTests.cs @@ -17,7 +17,7 @@ public void CreateGetDbDataReaderFieldValueExpression_BytesFieldType_ShouldCallG Expression.Constant(1), 1, "FieldA", - typeof(Byte[]) + typeof(byte[]) ); expression.ToString() @@ -59,20 +59,20 @@ public void CreateGetDbDataReaderFieldValueExpression_DateTimeOffsetFieldType_Sh } [Theory] - [InlineData(typeof(Boolean), "*DbDataReader*.GetBoolean(1)")] - [InlineData(typeof(Byte), "*DbDataReader*.GetByte(1)")] + [InlineData(typeof(bool), "*DbDataReader*.GetBoolean(1)")] + [InlineData(typeof(byte), "*DbDataReader*.GetByte(1)")] [InlineData(typeof(DateTime), "*DbDataReader*.GetDateTime(1)")] - [InlineData(typeof(Decimal), "*DbDataReader*.GetDecimal(1)")] - [InlineData(typeof(Double), "*DbDataReader*.GetDouble(1)")] - [InlineData(typeof(Single), "*DbDataReader*.GetFloat(1)")] + [InlineData(typeof(decimal), "*DbDataReader*.GetDecimal(1)")] + [InlineData(typeof(double), "*DbDataReader*.GetDouble(1)")] + [InlineData(typeof(float), "*DbDataReader*.GetFloat(1)")] [InlineData(typeof(Guid), "*DbDataReader*.GetGuid(1)")] - [InlineData(typeof(Int16), "*DbDataReader*.GetInt16(1)")] - [InlineData(typeof(Int32), "*DbDataReader*.GetInt32(1)")] - [InlineData(typeof(Int64), "*DbDataReader*.GetInt64(1)")] - [InlineData(typeof(String), "*DbDataReader*.GetString(1)")] + [InlineData(typeof(short), "*DbDataReader*.GetInt16(1)")] + [InlineData(typeof(int), "*DbDataReader*.GetInt32(1)")] + [InlineData(typeof(long), "*DbDataReader*.GetInt64(1)")] + [InlineData(typeof(string), "*DbDataReader*.GetString(1)")] public void CreateGetDbDataReaderFieldValueExpression_ShouldCallTypedGetMethod( Type fieldType, - String expectedExpression + string expectedExpression ) { var dataReader = Substitute.For(); @@ -158,25 +158,25 @@ public void CreateGetDbDataReaderFieldValueExpression_UnsupportedFieldType_Shoul } [Theory] - [InlineData(typeof(Boolean), nameof(DbDataReader.GetBoolean))] - [InlineData(typeof(Byte), nameof(DbDataReader.GetByte))] + [InlineData(typeof(bool), nameof(DbDataReader.GetBoolean))] + [InlineData(typeof(byte), nameof(DbDataReader.GetByte))] [InlineData(typeof(DateTime), nameof(DbDataReader.GetDateTime))] - [InlineData(typeof(Decimal), nameof(DbDataReader.GetDecimal))] - [InlineData(typeof(Double), nameof(DbDataReader.GetDouble))] - [InlineData(typeof(Single), nameof(DbDataReader.GetFloat))] + [InlineData(typeof(decimal), nameof(DbDataReader.GetDecimal))] + [InlineData(typeof(double), nameof(DbDataReader.GetDouble))] + [InlineData(typeof(float), nameof(DbDataReader.GetFloat))] [InlineData(typeof(Guid), nameof(DbDataReader.GetGuid))] - [InlineData(typeof(Int16), nameof(DbDataReader.GetInt16))] - [InlineData(typeof(Int32), nameof(DbDataReader.GetInt32))] - [InlineData(typeof(Int64), nameof(DbDataReader.GetInt64))] - [InlineData(typeof(String), nameof(DbDataReader.GetString))] - [InlineData(typeof(Byte[]), nameof(DbDataReader.GetValue))] + [InlineData(typeof(short), nameof(DbDataReader.GetInt16))] + [InlineData(typeof(int), nameof(DbDataReader.GetInt32))] + [InlineData(typeof(long), nameof(DbDataReader.GetInt64))] + [InlineData(typeof(string), nameof(DbDataReader.GetString))] + [InlineData(typeof(byte[]), nameof(DbDataReader.GetValue))] [InlineData(typeof(DateOnly), nameof(DbDataReader.GetValue))] [InlineData(typeof(DateTimeOffset), nameof(DbDataReader.GetValue))] [InlineData(typeof(TimeOnly), nameof(DbDataReader.GetValue))] [InlineData(typeof(TimeSpan), nameof(DbDataReader.GetValue))] public void CreateGetDbDataReaderFieldValueFunction_ShouldCallTheSameMethodAsTheExpression( Type fieldType, - String expectedDbDataReaderMethodName + string expectedDbDataReaderMethodName ) { var dataReader = Substitute.For(); @@ -237,7 +237,7 @@ public void DbDataReaderGetValueMethod_ShouldReferenceDbDataReaderGetValue() .Should().Be(nameof(DbDataReader.GetValue)); method.GetParameters().Select(p => (p.Name, p.ParameterType)) - .Should().BeEquivalentTo([("ordinal", typeof(Int32))]); + .Should().BeEquivalentTo([("ordinal", typeof(int))]); } [Fact] @@ -252,31 +252,31 @@ public void DbDataReaderIsDBNullMethod_ShouldReferenceDbDataReaderIsDBNull() .Should().Be(nameof(DbDataReader.IsDBNull)); method.GetParameters().Select(p => (p.Name, p.ParameterType)) - .Should().BeEquivalentTo([("ordinal", typeof(Int32))]); + .Should().BeEquivalentTo([("ordinal", typeof(int))]); } [Theory] - [InlineData(typeof(Boolean), true)] - [InlineData(typeof(Byte), true)] + [InlineData(typeof(bool), true)] + [InlineData(typeof(byte), true)] [InlineData(typeof(DateOnly), true)] [InlineData(typeof(DateTime), true)] - [InlineData(typeof(Decimal), true)] - [InlineData(typeof(Double), true)] - [InlineData(typeof(Single), true)] + [InlineData(typeof(decimal), true)] + [InlineData(typeof(double), true)] + [InlineData(typeof(float), true)] [InlineData(typeof(Guid), true)] - [InlineData(typeof(Int16), true)] - [InlineData(typeof(Int32), true)] - [InlineData(typeof(Int64), true)] - [InlineData(typeof(String), true)] - [InlineData(typeof(Byte[]), true)] + [InlineData(typeof(short), true)] + [InlineData(typeof(int), true)] + [InlineData(typeof(long), true)] + [InlineData(typeof(string), true)] + [InlineData(typeof(byte[]), true)] [InlineData(typeof(TimeSpan), true)] [InlineData(typeof(TimeOnly), true)] [InlineData(typeof(DateTimeOffset), true)] - [InlineData(typeof(Char), false)] + [InlineData(typeof(char), false)] [InlineData(typeof(BigInteger), false)] public void IsDbDataReaderTypedGetMethodAvailable_ShouldReturnWhetherTypedGetMethodIsAvailable( Type fieldType, - Boolean expectedResult + bool expectedResult ) => MaterializerFactoryHelper.IsDbDataReaderTypedGetMethodAvailable(fieldType) .Should().Be(expectedResult); @@ -284,7 +284,7 @@ Boolean expectedResult [Fact] public void MakeValueConverterConvertValueToTypeMethod_ShouldReferenceValueConverterConvertValueToType() { - var method = MaterializerFactoryHelper.MakeValueConverterConvertValueToTypeMethod(typeof(Int32)); + var method = MaterializerFactoryHelper.MakeValueConverterConvertValueToTypeMethod(typeof(int)); method.DeclaringType .Should().Be(typeof(ValueConverter)); @@ -293,10 +293,10 @@ public void MakeValueConverterConvertValueToTypeMethod_ShouldReferenceValueConve .Should().Be(nameof(ValueConverter.ConvertValueToType)); method.GetGenericArguments() - .Should().Equal(typeof(Int32)); + .Should().Equal(typeof(int)); method.GetParameters().Select(p => (p.Name, p.ParameterType)) - .Should().Equal(("value", typeof(Object))); + .Should().Equal(("value", typeof(object))); } [Fact] @@ -310,7 +310,7 @@ public void ShouldGuardAgainstNullArguments() Expression.Constant(1), 1, "FieldA", - typeof(Int32) + typeof(int) ) ); @@ -318,13 +318,13 @@ public void ShouldGuardAgainstNullArguments() MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueFunction( 1, "FieldA", - typeof(Int32) + typeof(int) ) ); ArgumentNullGuardVerifier.Verify(() => MaterializerFactoryHelper.IsDbDataReaderTypedGetMethodAvailable( - typeof(Int32) + typeof(int) ) ); } @@ -335,13 +335,13 @@ public void StringCharsProperty_ShouldReferenceStringCharsIndexer() var property = MaterializerFactoryHelper.StringCharsProperty; property.DeclaringType - .Should().Be(typeof(String)); + .Should().Be(typeof(string)); property.Name .Should().Be("Chars"); property.PropertyType - .Should().Be(typeof(Char)); + .Should().Be(typeof(char)); } [Fact] @@ -350,16 +350,16 @@ public void StringConcatMethod_ShouldReferenceStringConcatWithThreeStringParamet var method = MaterializerFactoryHelper.StringConcatMethod; method.DeclaringType - .Should().Be(typeof(String)); + .Should().Be(typeof(string)); method.Name .Should().Be(nameof(String.Concat)); method.GetParameters().Select(p => (p.Name, p.ParameterType)) - .Should().Equal(("str0", typeof(String)), ("str1", typeof(String)), ("str2", typeof(String))); + .Should().Equal(("str0", typeof(string)), ("str1", typeof(string)), ("str2", typeof(string))); method.ReturnType - .Should().Be(typeof(String)); + .Should().Be(typeof(string)); } [Fact] @@ -368,12 +368,12 @@ public void StringLengthProperty_ShouldReferenceStringLengthProperty() var property = MaterializerFactoryHelper.StringLengthProperty; property.DeclaringType - .Should().Be(typeof(String)); + .Should().Be(typeof(string)); property.Name .Should().Be(nameof(String.Length)); property.PropertyType - .Should().Be(typeof(Int32)); + .Should().Be(typeof(int)); } } diff --git a/tests/DbConnectionPlus.UnitTests/Materializers/ValueTupleMaterializerFactoryTests.cs b/tests/DbConnectionPlus.UnitTests/Materializers/ValueTupleMaterializerFactoryTests.cs index e146a91..ff189d9 100644 --- a/tests/DbConnectionPlus.UnitTests/Materializers/ValueTupleMaterializerFactoryTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Materializers/ValueTupleMaterializerFactoryTests.cs @@ -16,10 +16,10 @@ public void GetMaterializer_DataReaderFieldCountDoesNotMatchValueTupleFieldCount dataReader.FieldCount.Returns(2); - Invoking(() => ValueTupleMaterializerFactory.GetMaterializer<(Int32, Int32, Int32)>(dataReader)) + Invoking(() => ValueTupleMaterializerFactory.GetMaterializer<(int, int, int)>(dataReader)) .Should().Throw() .WithMessage( - $"The SQL statement returned 2 columns, but the value tuple type {typeof((Int32, Int32, Int32))} has " + + $"The SQL statement returned 2 columns, but the value tuple type {typeof((int, int, int))} has " + "3 fields. Make sure that the SQL statement returns the same number of columns as the number of " + "fields in the value tuple type.*" ); @@ -65,7 +65,7 @@ public void GetMaterializer_DataReaderHasNoFields_ShouldThrow() dataReader.FieldCount.Returns(0); - Invoking(() => ValueTupleMaterializerFactory.GetMaterializer>(dataReader)) + Invoking(() => ValueTupleMaterializerFactory.GetMaterializer>(dataReader)) .Should().Throw() .WithMessage("The SQL statement did not return any columns.*"); } @@ -122,16 +122,16 @@ public void Materializer_DataReaderHasCompatibleFieldTypes_ShouldConvertValues() dataReader.FieldCount.Returns(2); dataReader.GetName(0).Returns("Id"); - dataReader.GetFieldType(0).Returns(typeof(String)); + dataReader.GetFieldType(0).Returns(typeof(string)); dataReader.IsDBNull(0).Returns(false); dataReader.GetString(0).Returns(entityId.ToString()); dataReader.GetName(1).Returns("Enum"); - dataReader.GetFieldType(1).Returns(typeof(Decimal)); + dataReader.GetFieldType(1).Returns(typeof(decimal)); dataReader.IsDBNull(1).Returns(false); - dataReader.GetDecimal(1).Returns((Decimal)enumValue); + dataReader.GetDecimal(1).Returns((decimal)enumValue); - var materializer = ValueTupleMaterializerFactory.GetMaterializer<(Int64 Id, TestEnum Enum)>(dataReader); + var materializer = ValueTupleMaterializerFactory.GetMaterializer<(long Id, TestEnum Enum)>(dataReader); var entity = materializer(dataReader); @@ -152,9 +152,9 @@ public void Materializer_EnumValueTupleField_DataReaderContainsInteger_ShouldCon dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("Enum"); - dataReader.GetFieldType(0).Returns(typeof(Int32)); + dataReader.GetFieldType(0).Returns(typeof(int)); dataReader.IsDBNull(0).Returns(false); - dataReader.GetInt32(0).Returns((Int32)enumValue); + dataReader.GetInt32(0).Returns((int)enumValue); var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); @@ -172,7 +172,7 @@ public void Materializer_EnumValueTupleField_DataReaderContainsIntegerNotMatchin dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("Enum"); - dataReader.GetFieldType(0).Returns(typeof(Int32)); + dataReader.GetFieldType(0).Returns(typeof(int)); dataReader.IsDBNull(0).Returns(false); dataReader.GetInt32(0).Returns(999); @@ -188,7 +188,7 @@ public void Materializer_EnumValueTupleField_DataReaderContainsIntegerNotMatchin ) .WithInnerException() .WithMessage( - $"Could not convert the value '999' ({typeof(Int32)}) to an enum member of the type " + + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); } @@ -203,7 +203,7 @@ public void Materializer_EnumValueTupleField_DataReaderContainsString_ShouldConv dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("Enum"); - dataReader.GetFieldType(0).Returns(typeof(String)); + dataReader.GetFieldType(0).Returns(typeof(string)); dataReader.IsDBNull(0).Returns(false); dataReader.GetString(0).Returns(enumValue.ToString()); @@ -224,7 +224,7 @@ public void Materializer_EnumValueTupleField_DataReaderContainsStringNotMatching dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("Enum"); - dataReader.GetFieldType(0).Returns(typeof(String)); + dataReader.GetFieldType(0).Returns(typeof(string)); dataReader.IsDBNull(0).Returns(false); dataReader.GetString(0).Returns("NonExistent"); @@ -255,16 +255,16 @@ public void Materializer_MoreThan7FieldsValueTupleType_ShouldMaterializeNestedVa for (var i = 0; i < 15; i++) { dataReader.GetName(i).Returns($"Value{i + 1}"); - dataReader.GetFieldType(i).Returns(typeof(Int32)); + dataReader.GetFieldType(i).Returns(typeof(int)); dataReader.IsDBNull(i).Returns(false); dataReader.GetInt32(i).Returns(i + 1); } var materializer = ValueTupleMaterializerFactory .GetMaterializer<( - Int32, Int32, Int32, Int32, Int32, Int32, Int32, - Int32, Int32, Int32, Int32, Int32, Int32, Int32, - Int32 + int, int, int, int, int, int, int, + int, int, int, int, int, int, int, + int )>(dataReader); var valueTuple = materializer(dataReader); @@ -324,22 +324,22 @@ public void dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("Char"); - dataReader.GetFieldType(0).Returns(typeof(String)); + dataReader.GetFieldType(0).Returns(typeof(string)); dataReader.IsDBNull(0).Returns(false); - dataReader.GetString(0).Returns(String.Empty); + dataReader.GetString(0).Returns(string.Empty); - var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); + var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); Invoking(() => materializer(dataReader)) .Should().Throw() .WithMessage( "The column 'Char' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(Char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + $"the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException() .WithMessage( - $"Could not convert the string '' to the type {typeof(Char)}. The string must be exactly one " + + $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly one " + "character long." ); @@ -349,12 +349,12 @@ public void .Should().Throw() .WithMessage( "The column 'Char' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(Char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + $"the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char)}. The string must be exactly one " + + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly one " + "character long." ); } @@ -367,14 +367,14 @@ public void dataReader.FieldCount.Returns(1); - var character = Generate.Single(); + var character = Generate.Single(); dataReader.GetName(0).Returns("Char"); - dataReader.GetFieldType(0).Returns(typeof(String)); + dataReader.GetFieldType(0).Returns(typeof(string)); dataReader.IsDBNull(0).Returns(false); dataReader.GetString(0).Returns(character.ToString()); - var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); + var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); var valueTuple = materializer(dataReader); @@ -390,16 +390,16 @@ public void Materializer_NonNullableValueTupleField_DataReaderFieldContainsNull_ dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("Id"); - dataReader.GetFieldType(0).Returns(typeof(Int64)); + dataReader.GetFieldType(0).Returns(typeof(long)); dataReader.IsDBNull(0).Returns(true); - var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); + var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); Invoking(() => materializer(dataReader)) .Should().Throw() .WithMessage( "The column 'Id' returned by the SQL statement contains a NULL value, but the corresponding field " + - $"of the value tuple type {typeof(ValueTuple)} is non-nullable.*" + $"of the value tuple type {typeof(ValueTuple)} is non-nullable.*" ); } @@ -412,22 +412,22 @@ public void dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("Char"); - dataReader.GetFieldType(0).Returns(typeof(String)); + dataReader.GetFieldType(0).Returns(typeof(string)); dataReader.IsDBNull(0).Returns(false); - dataReader.GetString(0).Returns(String.Empty); + dataReader.GetString(0).Returns(string.Empty); - var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); + var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); Invoking(() => materializer(dataReader)) .Should().Throw() .WithMessage( "The column 'Char' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(Char?)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + $"the type {typeof(char?)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException() .WithMessage( - $"Could not convert the string '' to the type {typeof(Char?)}. The string must be exactly one " + + $"Could not convert the string '' to the type {typeof(char?)}. The string must be exactly one " + "character long." ); @@ -437,12 +437,12 @@ public void .Should().Throw() .WithMessage( "The column 'Char' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(Char?)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + $"the type {typeof(char?)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(Char?)}. The string must be exactly " + + $"Could not convert the string 'ab' to the type {typeof(char?)}. The string must be exactly " + "one character long." ); } @@ -455,14 +455,14 @@ public void dataReader.FieldCount.Returns(1); - var character = Generate.Single(); + var character = Generate.Single(); dataReader.GetName(0).Returns("Char"); - dataReader.GetFieldType(0).Returns(typeof(String)); + dataReader.GetFieldType(0).Returns(typeof(string)); dataReader.IsDBNull(0).Returns(false); dataReader.GetString(0).Returns(character.ToString()); - var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); + var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); var valueTuple = materializer(dataReader); @@ -477,12 +477,12 @@ public void Materializer_NullableValueTupleField_DataReaderFieldContainsNull_Sho dataReader.FieldCount.Returns(1); - dataReader.GetFieldType(0).Returns(typeof(Int64)); + dataReader.GetFieldType(0).Returns(typeof(long)); dataReader.GetName(0).Returns("Id"); dataReader.IsDBNull(0).Returns(true); dataReader.GetInt64(0).Throws(new SqlNullValueException()); - var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); + var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); var valueTuple = Invoking(() => materializer(dataReader)) .Should().NotThrow().Subject; @@ -503,13 +503,13 @@ public void Materializer_ShouldMaterialize() var ordinal = 0; dataReader.GetName(ordinal).Returns("Boolean"); - dataReader.GetFieldType(ordinal).Returns(typeof(Boolean)); + dataReader.GetFieldType(ordinal).Returns(typeof(bool)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetBoolean(ordinal).Returns(entity.BooleanValue); ordinal++; dataReader.GetName(ordinal).Returns("Char"); - dataReader.GetFieldType(ordinal).Returns(typeof(String)); + dataReader.GetFieldType(ordinal).Returns(typeof(string)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetString(ordinal).Returns(entity.CharValue.ToString()); @@ -521,12 +521,12 @@ public void Materializer_ShouldMaterialize() ordinal++; dataReader.GetName(ordinal).Returns("Nullable"); - dataReader.GetFieldType(ordinal).Returns(typeof(Decimal)); + dataReader.GetFieldType(ordinal).Returns(typeof(decimal)); dataReader.IsDBNull(ordinal).Returns(true); ordinal++; dataReader.GetName(ordinal).Returns("Enum"); - dataReader.GetFieldType(ordinal).Returns(typeof(String)); + dataReader.GetFieldType(ordinal).Returns(typeof(string)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetString(ordinal).Returns(entity.EnumValue.ToString()); @@ -538,12 +538,12 @@ public void Materializer_ShouldMaterialize() ordinal++; dataReader.GetName(ordinal).Returns("Int32"); - dataReader.GetFieldType(ordinal).Returns(typeof(Int32)); + dataReader.GetFieldType(ordinal).Returns(typeof(int)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt32(ordinal).Returns(entity.Int32Value); var materializer = ValueTupleMaterializerFactory - .GetMaterializer<(Boolean, Char, DateTime, Decimal?, TestEnum, Guid, Int32)>(dataReader); + .GetMaterializer<(bool, char, DateTime, decimal?, TestEnum, Guid, int)>(dataReader); var valueTuple = materializer(dataReader); @@ -576,14 +576,14 @@ public void Materializer_ShouldMaterializeBinaryData() dataReader.FieldCount.Returns(1); - var bytes = Generate.Single(); + var bytes = Generate.Single(); dataReader.GetName(0).Returns("Data"); - dataReader.GetFieldType(0).Returns(typeof(Byte[])); + dataReader.GetFieldType(0).Returns(typeof(byte[])); dataReader.IsDBNull(0).Returns(false); dataReader.GetValue(0).Returns(bytes); - var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); + var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); var valueTuple = materializer(dataReader); @@ -601,12 +601,12 @@ public void Materializer_ShouldSupportSingleFieldValueTupleType() dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("Boolean"); - dataReader.GetFieldType(0).Returns(typeof(Boolean)); + dataReader.GetFieldType(0).Returns(typeof(bool)); dataReader.IsDBNull(0).Returns(false); dataReader.GetBoolean(0).Returns(entity.BooleanValue); var materializer = ValueTupleMaterializerFactory - .GetMaterializer>(dataReader); + .GetMaterializer>(dataReader); var valueTuple = materializer(dataReader); @@ -626,13 +626,13 @@ public void ReflectionMaterializer_ShouldMaterializeTheSameValueTupleAsTheExpres var ordinal = 0; dataReader.GetName(ordinal).Returns("Boolean"); - dataReader.GetFieldType(ordinal).Returns(typeof(Boolean)); + dataReader.GetFieldType(ordinal).Returns(typeof(bool)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetBoolean(ordinal).Returns(entity.BooleanValue); ordinal++; dataReader.GetName(ordinal).Returns("Char"); - dataReader.GetFieldType(ordinal).Returns(typeof(String)); + dataReader.GetFieldType(ordinal).Returns(typeof(string)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetString(ordinal).Returns(entity.CharValue.ToString()); @@ -644,12 +644,12 @@ public void ReflectionMaterializer_ShouldMaterializeTheSameValueTupleAsTheExpres ordinal++; dataReader.GetName(ordinal).Returns("Nullable"); - dataReader.GetFieldType(ordinal).Returns(typeof(Decimal)); + dataReader.GetFieldType(ordinal).Returns(typeof(decimal)); dataReader.IsDBNull(ordinal).Returns(true); ordinal++; dataReader.GetName(ordinal).Returns("Enum"); - dataReader.GetFieldType(ordinal).Returns(typeof(String)); + dataReader.GetFieldType(ordinal).Returns(typeof(string)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetString(ordinal).Returns(entity.EnumValue.ToString()); @@ -661,15 +661,15 @@ public void ReflectionMaterializer_ShouldMaterializeTheSameValueTupleAsTheExpres ordinal++; dataReader.GetName(ordinal).Returns("Int32"); - dataReader.GetFieldType(ordinal).Returns(typeof(Int32)); + dataReader.GetFieldType(ordinal).Returns(typeof(int)); dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt32(ordinal).Returns(entity.Int32Value); var expressionMaterializer = ValueTupleMaterializerFactory - .GetMaterializer<(Boolean, Char, DateTime, Decimal?, TestEnum, Guid, Int32)>(dataReader); + .GetMaterializer<(bool, char, DateTime, decimal?, TestEnum, Guid, int)>(dataReader); var reflectionMaterializer = - GetReflectionMaterializer<(Boolean, Char, DateTime, Decimal?, TestEnum, Guid, Int32)>(dataReader); + GetReflectionMaterializer<(bool, char, DateTime, decimal?, TestEnum, Guid, int)>(dataReader); var valueTuple = reflectionMaterializer(dataReader); @@ -679,7 +679,7 @@ public void ReflectionMaterializer_ShouldMaterializeTheSameValueTupleAsTheExpres entity.BooleanValue, entity.CharValue, entity.DateTimeValue, - (Decimal?)null, + (decimal?)null, entity.EnumValue, entity.GuidValue, entity.Int32Value @@ -700,22 +700,22 @@ public void ReflectionMaterializer_MoreThan7FieldsValueTupleType_ShouldMateriali for (var i = 0; i < 15; i++) { dataReader.GetName(i).Returns($"Value{i + 1}"); - dataReader.GetFieldType(i).Returns(typeof(Int32)); + dataReader.GetFieldType(i).Returns(typeof(int)); dataReader.IsDBNull(i).Returns(false); dataReader.GetInt32(i).Returns(i + 1); } var expressionMaterializer = ValueTupleMaterializerFactory .GetMaterializer<( - Int32, Int32, Int32, Int32, Int32, Int32, Int32, - Int32, Int32, Int32, Int32, Int32, Int32, Int32, - Int32 + int, int, int, int, int, int, int, + int, int, int, int, int, int, int, + int )>(dataReader); var reflectionMaterializer = GetReflectionMaterializer<( - Int32, Int32, Int32, Int32, Int32, Int32, Int32, - Int32, Int32, Int32, Int32, Int32, Int32, Int32, - Int32 + int, int, int, int, int, int, int, + int, int, int, int, int, int, int, + int )>(dataReader); var valueTuple = reflectionMaterializer(dataReader); @@ -741,13 +741,13 @@ public void ReflectionMaterializer_EightFieldsValueTupleType_ShouldMaterializeNe for (var i = 0; i < 8; i++) { dataReader.GetName(i).Returns($"Value{i + 1}"); - dataReader.GetFieldType(i).Returns(typeof(Int32)); + dataReader.GetFieldType(i).Returns(typeof(int)); dataReader.IsDBNull(i).Returns(false); dataReader.GetInt32(i).Returns(i + 1); } var materializer = - GetReflectionMaterializer<(Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32)>(dataReader); + GetReflectionMaterializer<(int, int, int, int, int, int, int, int)>(dataReader); materializer(dataReader) .Should().Be((1, 2, 3, 4, 5, 6, 7, 8)); @@ -764,16 +764,16 @@ public void ReflectionMaterializer_DataReaderHasCompatibleFieldTypes_ShouldConve dataReader.FieldCount.Returns(2); dataReader.GetName(0).Returns("Id"); - dataReader.GetFieldType(0).Returns(typeof(String)); + dataReader.GetFieldType(0).Returns(typeof(string)); dataReader.IsDBNull(0).Returns(false); dataReader.GetString(0).Returns(entityId.ToString()); dataReader.GetName(1).Returns("Enum"); - dataReader.GetFieldType(1).Returns(typeof(Decimal)); + dataReader.GetFieldType(1).Returns(typeof(decimal)); dataReader.IsDBNull(1).Returns(false); - dataReader.GetDecimal(1).Returns((Decimal)enumValue); + dataReader.GetDecimal(1).Returns((decimal)enumValue); - var materializer = GetReflectionMaterializer<(Int64 Id, TestEnum Enum)>(dataReader); + var materializer = GetReflectionMaterializer<(long Id, TestEnum Enum)>(dataReader); var valueTuple = materializer(dataReader); @@ -791,14 +791,14 @@ public void ReflectionMaterializer_ShouldMaterializeBinaryData() dataReader.FieldCount.Returns(1); - var bytes = Generate.Single(); + var bytes = Generate.Single(); dataReader.GetName(0).Returns("Data"); - dataReader.GetFieldType(0).Returns(typeof(Byte[])); + dataReader.GetFieldType(0).Returns(typeof(byte[])); dataReader.IsDBNull(0).Returns(false); dataReader.GetValue(0).Returns(bytes); - var materializer = GetReflectionMaterializer>(dataReader); + var materializer = GetReflectionMaterializer>(dataReader); materializer(dataReader).Item1 .Should().BeEquivalentTo(bytes); @@ -812,11 +812,11 @@ public void ReflectionMaterializer_NonNullableValueTupleField_DataReaderFieldCon dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("Id"); - dataReader.GetFieldType(0).Returns(typeof(Int64)); + dataReader.GetFieldType(0).Returns(typeof(long)); dataReader.IsDBNull(0).Returns(true); - var expressionMaterializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); - var reflectionMaterializer = GetReflectionMaterializer>(dataReader); + var expressionMaterializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); + var reflectionMaterializer = GetReflectionMaterializer>(dataReader); var expectedMessage = Invoking(() => expressionMaterializer(dataReader)) .Should().Throw().Which.Message; @@ -825,7 +825,7 @@ public void ReflectionMaterializer_NonNullableValueTupleField_DataReaderFieldCon .Should().Throw() .WithMessage( "The column 'Id' returned by the SQL statement contains a NULL value, but the corresponding field " + - $"of the value tuple type {typeof(ValueTuple)} is non-nullable." + $"of the value tuple type {typeof(ValueTuple)} is non-nullable." ) .And.Message .Should().Be(expectedMessage); @@ -838,12 +838,12 @@ public void ReflectionMaterializer_NullableValueTupleField_DataReaderFieldContai dataReader.FieldCount.Returns(1); - dataReader.GetFieldType(0).Returns(typeof(Int64)); + dataReader.GetFieldType(0).Returns(typeof(long)); dataReader.GetName(0).Returns("Id"); dataReader.IsDBNull(0).Returns(true); dataReader.GetInt64(0).Throws(new SqlNullValueException()); - var materializer = GetReflectionMaterializer>(dataReader); + var materializer = GetReflectionMaterializer>(dataReader); Invoking(() => materializer(dataReader)) .Should().NotThrow().Subject.Item1 @@ -858,7 +858,7 @@ public void ReflectionMaterializer_DataReaderFieldValueCannotBeConverted_ShouldT dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("Enum"); - dataReader.GetFieldType(0).Returns(typeof(Int32)); + dataReader.GetFieldType(0).Returns(typeof(int)); dataReader.IsDBNull(0).Returns(false); dataReader.GetInt32(0).Returns(999); @@ -877,7 +877,7 @@ public void ReflectionMaterializer_DataReaderFieldValueCannotBeConverted_ShouldT ) .WithInnerException() .WithMessage( - $"Could not convert the value '999' ({typeof(Int32)}) to an enum member of the type " + + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); @@ -894,16 +894,16 @@ public void ReflectionMaterializer_DataReaderFieldHasNoName_ShouldReportThePosit dataReader.FieldCount.Returns(2); dataReader.GetName(0).Returns(""); - dataReader.GetFieldType(0).Returns(typeof(Int64)); + dataReader.GetFieldType(0).Returns(typeof(long)); dataReader.IsDBNull(0).Returns(false); dataReader.GetInt64(0).Returns(Generate.Id()); dataReader.GetName(1).Returns(""); - dataReader.GetFieldType(1).Returns(typeof(Int64)); + dataReader.GetFieldType(1).Returns(typeof(long)); dataReader.IsDBNull(1).Returns(true); - var expressionMaterializer = ValueTupleMaterializerFactory.GetMaterializer<(Int64, Int64)>(dataReader); - var reflectionMaterializer = GetReflectionMaterializer<(Int64, Int64)>(dataReader); + var expressionMaterializer = ValueTupleMaterializerFactory.GetMaterializer<(long, long)>(dataReader); + var reflectionMaterializer = GetReflectionMaterializer<(long, long)>(dataReader); var expectedMessage = Invoking(() => expressionMaterializer(dataReader)) .Should().Throw().Which.Message; @@ -912,7 +912,7 @@ public void ReflectionMaterializer_DataReaderFieldHasNoName_ShouldReportThePosit .Should().Throw() .WithMessage( "The 2nd column returned by the SQL statement contains a NULL value, but the corresponding field " + - $"of the value tuple type {typeof((Int64, Int64))} is non-nullable." + $"of the value tuple type {typeof((long, long))} is non-nullable." ) .And.Message .Should().Be(expectedMessage); @@ -922,17 +922,17 @@ public void ReflectionMaterializer_DataReaderFieldHasNoName_ShouldReportThePosit public void ShouldGuardAgainstNullArguments() { ArgumentNullGuardVerifier.Verify(() => - ValueTupleMaterializerFactory.GetMaterializer>(Substitute.For()) + ValueTupleMaterializerFactory.GetMaterializer>(Substitute.For()) ); var dataReader = Substitute.For(); dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("Value"); - dataReader.GetFieldType(0).Returns(typeof(Int32)); + dataReader.GetFieldType(0).Returns(typeof(int)); ArgumentNullGuardVerifier.Verify(() => - ValueTupleMaterializerFactory.CreateReflectionMaterializer>( + ValueTupleMaterializerFactory.CreateReflectionMaterializer>( dataReader, dataReader.GetFieldNames(), dataReader.GetFieldTypes() diff --git a/tests/DbConnectionPlus.UnitTests/Mocks/MockDbParameterCollection.cs b/tests/DbConnectionPlus.UnitTests/Mocks/MockDbParameterCollection.cs index b8a1117..6070e5f 100644 --- a/tests/DbConnectionPlus.UnitTests/Mocks/MockDbParameterCollection.cs +++ b/tests/DbConnectionPlus.UnitTests/Mocks/MockDbParameterCollection.cs @@ -6,13 +6,13 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.Mocks; public class MockDbParameterCollection : DbParameterCollection { /// - public override Int32 Count => this.parameters.Count; + public override int Count => this.parameters.Count; /// - public override Object SyncRoot => ((ICollection)this.parameters).SyncRoot; + public override object SyncRoot => ((ICollection)this.parameters).SyncRoot; /// - public override Int32 Add(Object value) + public override int Add(object value) { this.parameters.Add((DbParameter)value); return this.Count - 1; @@ -25,23 +25,23 @@ public override Int32 Add(Object value) public override void Clear() => this.parameters.Clear(); /// - public override Boolean Contains(Object value) => this.parameters.Contains(value); + public override bool Contains(object value) => this.parameters.Contains(value); /// - public override Boolean Contains(String value) => this.IndexOf(value) != -1; + public override bool Contains(string value) => this.IndexOf(value) != -1; /// - public override void CopyTo(Array array, Int32 index) => + public override void CopyTo(Array array, int index) => this.parameters.CopyTo((DbParameter[])array, index); /// public override IEnumerator GetEnumerator() => this.parameters.GetEnumerator(); /// - public override Int32 IndexOf(Object value) => this.parameters.IndexOf((DbParameter)value); + public override int IndexOf(object value) => this.parameters.IndexOf((DbParameter)value); /// - public override Int32 IndexOf(String parameterName) + public override int IndexOf(string parameterName) { for (var index = 0; index < this.parameters.Count; ++index) { @@ -55,35 +55,35 @@ public override Int32 IndexOf(String parameterName) } /// - public override void Insert(Int32 index, Object value) => + public override void Insert(int index, object value) => this.parameters.Insert(index, (DbParameter)value); /// - public override void Remove(Object value) => this.parameters.Remove((DbParameter)value); + public override void Remove(object value) => this.parameters.Remove((DbParameter)value); /// - public override void RemoveAt(Int32 index) => this.parameters.RemoveAt(index); + public override void RemoveAt(int index) => this.parameters.RemoveAt(index); /// - public override void RemoveAt(String parameterName) => + public override void RemoveAt(string parameterName) => this.RemoveAt(this.IndexOfChecked(parameterName)); /// - protected override DbParameter GetParameter(Int32 index) => this.parameters[index]; + protected override DbParameter GetParameter(int index) => this.parameters[index]; /// - protected override DbParameter GetParameter(String parameterName) => + protected override DbParameter GetParameter(string parameterName) => this.GetParameter(this.IndexOfChecked(parameterName)); /// - protected override void SetParameter(Int32 index, DbParameter value) => + protected override void SetParameter(int index, DbParameter value) => this.parameters[index] = value; /// - protected override void SetParameter(String parameterName, DbParameter value) => + protected override void SetParameter(string parameterName, DbParameter value) => this.SetParameter(this.IndexOfChecked(parameterName), value); - private Int32 IndexOfChecked(String parameterName) + private int IndexOfChecked(string parameterName) { var index = this.IndexOf(parameterName); return index != -1 ? index : throw new IndexOutOfRangeException(); diff --git a/tests/DbConnectionPlus.UnitTests/Readers/CommandDisposingDataReaderDecoratorTests.cs b/tests/DbConnectionPlus.UnitTests/Readers/CommandDisposingDataReaderDecoratorTests.cs index 0ed80bc..cc79dce 100644 --- a/tests/DbConnectionPlus.UnitTests/Readers/CommandDisposingDataReaderDecoratorTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Readers/CommandDisposingDataReaderDecoratorTests.cs @@ -50,12 +50,12 @@ public void GetFieldValue_ShouldForwardToDecoratedReader() var ordinal = Generate.SmallNumber(); var returnValue = Generate.SmallNumber(); - this.decoratedReader.GetFieldValue(ordinal).Returns(returnValue); + this.decoratedReader.GetFieldValue(ordinal).Returns(returnValue); - this.decorator.GetFieldValue(ordinal) + this.decorator.GetFieldValue(ordinal) .Should().Be(returnValue); - this.decoratedReader.Received().GetFieldValue(ordinal); + this.decoratedReader.Received().GetFieldValue(ordinal); } [Fact] @@ -64,19 +64,19 @@ public async Task GetFieldValueAsync_ShouldForwardToDecoratedReader() var ordinal = Generate.SmallNumber(); var returnValue = Generate.SmallNumber(); - this.decoratedReader.GetFieldValueAsync(ordinal, CancellationToken.None) + this.decoratedReader.GetFieldValueAsync(ordinal, CancellationToken.None) .Returns(Task.FromResult(returnValue)); - (await this.decorator.GetFieldValueAsync(ordinal, CancellationToken.None)) + (await this.decorator.GetFieldValueAsync(ordinal, CancellationToken.None)) .Should().Be(returnValue); - await this.decoratedReader.Received().GetFieldValueAsync(ordinal, CancellationToken.None); + await this.decoratedReader.Received().GetFieldValueAsync(ordinal, CancellationToken.None); } [Fact] public void ShouldForwardAllMethodCallsToDecoratedReader() { - var exceptions = new HashSet + var exceptions = new HashSet { nameof(CommandDisposingDataReaderDecorator.Dispose), nameof(CommandDisposingDataReaderDecorator.DisposeAsync), diff --git a/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderOptionsTests.cs b/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderOptionsTests.cs index 5e9cb1b..53e2f75 100644 --- a/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderOptionsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderOptionsTests.cs @@ -20,7 +20,7 @@ public void GetFieldType_CharPropertyReadAsString_ShouldReturnString() ); reader.GetFieldType(reader.GetOrdinal("CharValue")) - .Should().Be(typeof(String)); + .Should().Be(typeof(string)); } [Fact] @@ -37,7 +37,7 @@ public void GetFieldType_EnumValuesSerializedAsIntegers_ShouldReturnInt32() ); reader.GetFieldType(0) - .Should().Be(typeof(Int32)); + .Should().Be(typeof(int)); } [Fact] @@ -54,7 +54,7 @@ public void GetFieldType_EnumValuesSerializedAsStrings_ShouldReturnString() ); reader.GetFieldType(0) - .Should().Be(typeof(String)); + .Should().Be(typeof(string)); } [Fact] @@ -74,14 +74,14 @@ public void GetInt32_EnumValuesSerialized_ShouldReturnEnumAsInt32() .Should().BeTrue(); reader.GetInt32(0) - .Should().Be((Int32)entity.Enum); + .Should().Be((int)entity.Enum); } } [Fact] public void GetString_CharPropertyReadAsString_ShouldConvertToString() { - Entity[] entities = [new() { CharValue = Generate.Single() }]; + Entity[] entities = [new() { CharValue = Generate.Single() }]; using var reader = CreateReader( typeof(Entity), @@ -119,7 +119,7 @@ public void GetString_EnumValuesSerialized_ShouldReturnEnumAsString() [Fact] public void GetValues_CharPropertyReadAsString_ShouldConvertToString() { - Entity[] entities = [new() { CharValue = Generate.Single() }]; + Entity[] entities = [new() { CharValue = Generate.Single() }]; using var reader = CreateReader( typeof(Entity), @@ -129,7 +129,7 @@ public void GetValues_CharPropertyReadAsString_ShouldConvertToString() reader.Read(); - var values = new Object[reader.FieldCount]; + var values = new object[reader.FieldCount]; reader.GetValues(values); @@ -155,13 +155,13 @@ public void GetValues_EnumValuesSerializedAsIntegers_ShouldSerializeEnumsAsInteg reader.Read() .Should().BeTrue(); - var values = new Object[reader.FieldCount]; + var values = new object[reader.FieldCount]; reader.GetValues(values) .Should().Be(reader.FieldCount); values[0] - .Should().Be((Int32)entity.Enum); + .Should().Be((int)entity.Enum); } } @@ -183,7 +183,7 @@ public void GetValues_EnumValuesSerializedAsStrings_ShouldSerializeEnumsAsString reader.Read() .Should().BeTrue(); - var values = new Object[reader.FieldCount]; + var values = new object[reader.FieldCount]; reader.GetValues(values) .Should().Be(reader.FieldCount); @@ -199,14 +199,14 @@ public void GetValues_NoOptions_ShouldReturnRawEnumAndCharValues() var entity = new Entity { EnumValue = Generate.Single(), - CharValue = Generate.Single() + CharValue = Generate.Single() }; using var reader = CreateReader(typeof(Entity), new[] { entity }, EnumerableReaderOptions.None); reader.Read(); - var values = new Object[reader.FieldCount]; + var values = new object[reader.FieldCount]; reader.GetValues(values); values[reader.GetOrdinal("EnumValue")] diff --git a/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderTests.cs b/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderTests.cs index 5356233..fcd1685 100644 --- a/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderTests.cs @@ -12,8 +12,8 @@ public class EnumerableReaderTests : UnitTestsBase /// public EnumerableReaderTests() { - this.testValues = Generate.Single(); - this.enumerableReader = new(this.testValues, typeof(Int32), FieldName); + this.testValues = Generate.Single(); + this.enumerableReader = new(this.testValues, typeof(int), FieldName); } [Fact] @@ -36,7 +36,7 @@ public void Close_ShouldDisposeEnumerator() enumerable.GetEnumerator().Returns(enumerator); - var reader = new EnumerableReader(enumerable, typeof(Int32), FieldName); + var reader = new EnumerableReader(enumerable, typeof(int), FieldName); reader.Close(); @@ -51,7 +51,7 @@ public async Task CloseAsync_ShouldDisposeEnumerator() enumerable.GetEnumerator().Returns(enumerator); - var reader = new EnumerableReader(enumerable, typeof(Int32), FieldName); + var reader = new EnumerableReader(enumerable, typeof(int), FieldName); await reader.CloseAsync(); @@ -61,10 +61,10 @@ public async Task CloseAsync_ShouldDisposeEnumerator() [Fact] public void Constructor_FieldNameEmptyOrWhitespace_ShouldThrow() { - Invoking(() => new EnumerableReader(this.testValues, typeof(Int32), String.Empty)) + Invoking(() => new EnumerableReader(this.testValues, typeof(int), string.Empty)) .Should().Throw(); - Invoking(() => new EnumerableReader(this.testValues, typeof(Int32), " ")) + Invoking(() => new EnumerableReader(this.testValues, typeof(int), " ")) .Should().Throw(); } @@ -81,7 +81,7 @@ public void Dispose_ShouldDisposeEnumerator() enumerable.GetEnumerator().Returns(enumerator); - var reader = new EnumerableReader(enumerable, typeof(Int32), FieldName); + var reader = new EnumerableReader(enumerable, typeof(int), FieldName); reader.Dispose(); @@ -96,7 +96,7 @@ public async Task DisposeAsync_ShouldDisposeEnumerator() enumerable.GetEnumerator().Returns(enumerator); - var reader = new EnumerableReader(enumerable, typeof(Int32), FieldName); + var reader = new EnumerableReader(enumerable, typeof(int), FieldName); await reader.DisposeAsync(); @@ -128,7 +128,7 @@ public void GetFieldType_InvalidOrdinal_ShouldThrow() => [Fact] public void GetFieldType_ValidOrdinal_ShouldReturnValuesTypePassedToConstructor() => this.enumerableReader.GetFieldType(0) - .Should().Be(typeof(Int32)); + .Should().Be(typeof(int)); [Fact] public void GetName_InvalidOrdinal_ShouldThrow() => @@ -158,18 +158,18 @@ public void GetOrdinal_ValidFieldName_ShouldReturnOrdinal() => [Fact] public void GetTypedValue_SingleColumn_ShouldReturnCurrentValue() { - AssertSingleColumnAccessor(true, typeof(Boolean), a => a.GetBoolean(0)); - AssertSingleColumnAccessor((Byte)7, typeof(Byte), a => a.GetByte(0)); - AssertSingleColumnAccessor('R', typeof(Char), a => a.GetChar(0)); + AssertSingleColumnAccessor(true, typeof(bool), a => a.GetBoolean(0)); + AssertSingleColumnAccessor((byte)7, typeof(byte), a => a.GetByte(0)); + AssertSingleColumnAccessor('R', typeof(char), a => a.GetChar(0)); AssertSingleColumnAccessor(new DateTime(2026, 8, 20), typeof(DateTime), a => a.GetDateTime(0)); - AssertSingleColumnAccessor(12.34m, typeof(Decimal), a => a.GetDecimal(0)); - AssertSingleColumnAccessor(12.34d, typeof(Double), a => a.GetDouble(0)); - AssertSingleColumnAccessor(12.34f, typeof(Single), a => a.GetFloat(0)); + AssertSingleColumnAccessor(12.34m, typeof(decimal), a => a.GetDecimal(0)); + AssertSingleColumnAccessor(12.34d, typeof(double), a => a.GetDouble(0)); + AssertSingleColumnAccessor(12.34f, typeof(float), a => a.GetFloat(0)); AssertSingleColumnAccessor(Guid.NewGuid(), typeof(Guid), a => a.GetGuid(0)); - AssertSingleColumnAccessor((Int16)7, typeof(Int16), a => a.GetInt16(0)); - AssertSingleColumnAccessor(7, typeof(Int32), a => a.GetInt32(0)); - AssertSingleColumnAccessor(7L, typeof(Int64), a => a.GetInt64(0)); - AssertSingleColumnAccessor("value", typeof(String), a => a.GetString(0)); + AssertSingleColumnAccessor((short)7, typeof(short), a => a.GetInt16(0)); + AssertSingleColumnAccessor(7, typeof(int), a => a.GetInt32(0)); + AssertSingleColumnAccessor(7L, typeof(long), a => a.GetInt64(0)); + AssertSingleColumnAccessor("value", typeof(string), a => a.GetString(0)); } [Fact] @@ -207,7 +207,7 @@ public void GetValues_BufferTooSmall_ShouldThrow() [Fact] public void GetValues_ShouldAlwaysReturnOne() { - var values = new Object[1]; + var values = new object[1]; foreach (var _ in this.testValues) { @@ -221,7 +221,7 @@ public void GetValues_ShouldAlwaysReturnOne() [Fact] public void GetValues_ShouldFillBufferWithValue() { - var buffer = new Object[1]; + var buffer = new object[1]; foreach (var value in this.testValues) { @@ -266,7 +266,7 @@ public void GetValues_MultiColumnShortBuffer_ShouldFillAvailableEntries() reader.Read(); - var values = new Object[2]; + var values = new object[2]; reader.GetValues(values) .Should().Be(values.Length); @@ -347,8 +347,8 @@ public void IsDBNull_InvalidOrdinal_ShouldThrow() => [Fact] public void IsDBNull_ValidOrdinal_ShouldReturnWhetherCurrentValueIsNull() { - var valuesWithNulls = Generate.MultipleNullable(); - var readerWithNulls = new EnumerableReader(valuesWithNulls, typeof(Int32), FieldName); + var valuesWithNulls = Generate.MultipleNullable(); + var readerWithNulls = new EnumerableReader(valuesWithNulls, typeof(int), FieldName); foreach (var value in valuesWithNulls) { @@ -394,14 +394,14 @@ public void RecordsAffected_ShouldAlwaysReturnMinusOne() => [Fact] public void ShouldGuardAgainstNullArguments() => - ArgumentNullGuardVerifier.Verify(() => new EnumerableReader(this.testValues, typeof(Int32), FieldName)); + ArgumentNullGuardVerifier.Verify(() => new EnumerableReader(this.testValues, typeof(int), FieldName)); private static void AssertSingleColumnAccessor( - Object value, + object value, [DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] Type valuesType, - Func accessor + Func accessor ) { using var reader = new EnumerableReader(new[] { value }, valuesType, FieldName); @@ -413,6 +413,6 @@ Func accessor } private readonly EnumerableReader enumerableReader; - private readonly Int32[] testValues; - private const String FieldName = "Value"; + private readonly int[] testValues; + private const string FieldName = "Value"; } diff --git a/tests/DbConnectionPlus.UnitTests/SqlStatements/InterpolatedSqlStatementTests.cs b/tests/DbConnectionPlus.UnitTests/SqlStatements/InterpolatedSqlStatementTests.cs index c5467f8..c2a005e 100644 --- a/tests/DbConnectionPlus.UnitTests/SqlStatements/InterpolatedSqlStatementTests.cs +++ b/tests/DbConnectionPlus.UnitTests/SqlStatements/InterpolatedSqlStatementTests.cs @@ -24,7 +24,7 @@ public void AppendFormatted_InterpolatedParameter_ShouldStoreParameter() [Fact] public void AppendFormatted_InterpolatedParameter_ShouldSupportComplexExpressions() { - const Double baseDiscount = 0.1; + const double baseDiscount = 0.1; var entityIds = Generate.Ids(20); InterpolatedSqlStatement statement = @@ -79,7 +79,7 @@ public void AppendFormatted_InterpolatedTemporaryTables_ShouldStoreTemporaryTabl .Should().BeEquivalentTo(entityIds); table1.ValuesType - .Should().Be(typeof(Int64)); + .Should().Be(typeof(long)); statement.Fragments[2] .Should().Be(new Literal($"{Environment.NewLine}UNION{Environment.NewLine}SELECT Id FROM ")); @@ -318,7 +318,7 @@ public void Fragments_ShouldGetFragments() .Should().BeEquivalentTo(entityIds); table1.ValuesType - .Should().Be(typeof(Int64)); + .Should().Be(typeof(long)); statement.Fragments[8] .Should().Be(new Literal($"{Environment.NewLine}UNION{Environment.NewLine}SELECT Id FROM ")); @@ -339,13 +339,13 @@ public void Fragments_ShouldGetFragments() [Fact] public void FromString_EmptyString_ShouldCreateEmptyStatement() { - var statement = InterpolatedSqlStatement.FromString(String.Empty); + var statement = InterpolatedSqlStatement.FromString(string.Empty); statement.Fragments .Should().HaveCount(1); statement.Fragments[0] - .Should().Be(new Literal(String.Empty)); + .Should().Be(new Literal(string.Empty)); } [Fact] @@ -364,7 +364,7 @@ public void FromString_ShouldCreateSqlStatementFromString() public void ImplicitConversion_NullValue_ShouldThrow() => Invoking(() => { - const String? sql = null; + const string? sql = null; #pragma warning disable RCS1124 // Inline local variable InterpolatedSqlStatement statement = sql!; #pragma warning restore RCS1124 // Inline local variable @@ -388,7 +388,7 @@ public void ImplicitConversion_ShouldCreateSqlStatementFromString() [Fact] public void ShouldGuardAgainstNullArguments() { - (String, Object?)[] parameters = [("Parameter1", "Value1")]; + (string, object?)[] parameters = [("Parameter1", "Value1")]; ArgumentNullGuardVerifier.Verify(() => new InterpolatedSqlStatement("SELECT 1", parameters)); ArgumentNullGuardVerifier.Verify(() => InterpolatedSqlStatement.FromString("SELECT 1")); @@ -420,7 +420,7 @@ public void TemporaryTables_ShouldGetInterpolatedTemporaryTables() .Should().BeEquivalentTo(entityIds); table1.ValuesType - .Should().Be(typeof(Int64)); + .Should().Be(typeof(long)); } [Fact] @@ -433,9 +433,9 @@ public void ToString_ShouldReturnStringRepresentationOfStatement() new(3, "C", TestEnum.Value3) }; - List ids = [1, 2, 3]; + List ids = [1, 2, 3]; - const String name = "B"; + const string name = "B"; const TestEnum enumValue = TestEnum.Value2; InterpolatedSqlStatement statement = $""" @@ -475,7 +475,7 @@ SELECT Value .Should().Be(ids); idsTable.ValuesType - .Should().Be(typeof(Int32)); + .Should().Be(typeof(int)); statement.ToString() .Should().Be( diff --git a/tests/DbConnectionPlus.UnitTests/StatementMethodTestsBase.cs b/tests/DbConnectionPlus.UnitTests/StatementMethodTestsBase.cs index d83d1a0..6280b3b 100644 --- a/tests/DbConnectionPlus.UnitTests/StatementMethodTestsBase.cs +++ b/tests/DbConnectionPlus.UnitTests/StatementMethodTestsBase.cs @@ -40,7 +40,7 @@ await this.asyncTestMethod( ); this.MockInterceptDbCommand.Received().Invoke( - Arg.Is(cmd => cmd.CommandTimeout == (Int32)timeout.TotalSeconds), + Arg.Is(cmd => cmd.CommandTimeout == (int)timeout.TotalSeconds), Arg.Any>() ); } @@ -98,7 +98,7 @@ public void SyncMethod_ShouldUseCommandTimeout() ); this.MockInterceptDbCommand.Received().Invoke( - Arg.Is(cmd => cmd.CommandTimeout == (Int32)timeout.TotalSeconds), + Arg.Is(cmd => cmd.CommandTimeout == (int)timeout.TotalSeconds), Arg.Any>() ); } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/Entity.cs b/tests/DbConnectionPlus.UnitTests/TestData/Entity.cs index 69598e0..be02316 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/Entity.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/Entity.cs @@ -2,27 +2,27 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public record Entity { - public Boolean BooleanValue { get; set; } - public Byte[] BytesValue { get; set; } = null!; - public Byte ByteValue { get; set; } - public Char CharValue { get; set; } + public bool BooleanValue { get; set; } + public byte[] BytesValue { get; set; } = null!; + public byte ByteValue { get; set; } + public char CharValue { get; set; } public DateOnly DateOnlyValue { get; set; } public DateTime DateTimeValue { get; set; } - public Decimal DecimalValue { get; set; } - public Double DoubleValue { get; set; } + public decimal DecimalValue { get; set; } + public double DoubleValue { get; set; } public TestEnum EnumValue { get; set; } public Guid GuidValue { get; set; } [Key] - public Int64 Id { get; set; } + public long Id { get; set; } - public Int16 Int16Value { get; set; } - public Int32 Int32Value { get; set; } - public Int64 Int64Value { get; set; } + public short Int16Value { get; set; } + public int Int32Value { get; set; } + public long Int64Value { get; set; } - public Boolean? NullableBooleanValue { get; set; } - public Single SingleValue { get; set; } - public String StringValue { get; set; } = null!; + public bool? NullableBooleanValue { get; set; } + public float SingleValue { get; set; } + public string StringValue { get; set; } = null!; public TimeOnly TimeOnlyValue { get; set; } public TimeSpan TimeSpanValue { get; set; } } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithDateTimeOffset.cs b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithDateTimeOffset.cs index 45714a2..a86a100 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithDateTimeOffset.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithDateTimeOffset.cs @@ -5,5 +5,5 @@ public record EntityWithDateTimeOffset public DateTimeOffset DateTimeOffsetValue { get; set; } [Key] - public Int64 Id { get; set; } + public long Id { get; set; } } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithDifferentCasingProperties.cs b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithDifferentCasingProperties.cs index 1eb1226..ba1df09 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithDifferentCasingProperties.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithDifferentCasingProperties.cs @@ -4,30 +4,30 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public record EntityWithDifferentCasingProperties { - public Boolean BooleanVALUE { get; set; } - public Byte[] BytesVALUE { get; set; } = null!; - public Byte ByteVALUE { get; set; } - public Char CharVALUE { get; set; } + public bool BooleanVALUE { get; set; } + public byte[] BytesVALUE { get; set; } = null!; + public byte ByteVALUE { get; set; } + public char CharVALUE { get; set; } public DateOnly DateOnlyVALUE { get; set; } public DateTime DateTimeVALUE { get; set; } - public Decimal DecimalVALUE { get; set; } - public Double DoubleVALUE { get; set; } + public decimal DecimalVALUE { get; set; } + public double DoubleVALUE { get; set; } public TestEnum EnumVALUE { get; set; } public Guid GuidVALUE { get; set; } [Key] - public Int64 Id { get; set; } + public long Id { get; set; } - public Int16 Int16VALUE { get; set; } - public Int32 Int32VALUE { get; set; } - public Int64 Int64VALUE { get; set; } + public short Int16VALUE { get; set; } + public int Int32VALUE { get; set; } + public long Int64VALUE { get; set; } [NotMapped] - public String? NotMappedProperty { get; set; } + public string? NotMappedProperty { get; set; } - public Boolean? NullableBooleanVALUE { get; set; } - public Single SingleVALUE { get; set; } - public String StringVALUE { get; set; } = null!; + public bool? NullableBooleanVALUE { get; set; } + public float SingleVALUE { get; set; } + public string StringVALUE { get; set; } = null!; public TimeOnly TimeOnlyVALUE { get; set; } public TimeSpan TimeSpanVALUE { get; set; } } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithEnumStoredAsInteger.cs b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithEnumStoredAsInteger.cs index d8efbd0..122270f 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithEnumStoredAsInteger.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithEnumStoredAsInteger.cs @@ -5,5 +5,5 @@ public record EntityWithEnumStoredAsInteger public TestEnum Enum { get; set; } [Key] - public Int64 Id { get; set; } + public long Id { get; set; } } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithEnumStoredAsString.cs b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithEnumStoredAsString.cs index 4f760d2..0307132 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithEnumStoredAsString.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithEnumStoredAsString.cs @@ -5,5 +5,5 @@ public record EntityWithEnumStoredAsString public TestEnum Enum { get; set; } [Key] - public Int64 Id { get; set; } + public long Id { get; set; } } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithMultipleIdentityProperties.cs b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithMultipleIdentityProperties.cs index 5046068..cd5651e 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithMultipleIdentityProperties.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithMultipleIdentityProperties.cs @@ -3,8 +3,8 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public class EntityWithMultipleIdentityProperties { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public Int64 Identity1 { get; set; } + public long Identity1 { get; set; } [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public Int64 Identity2 { get; set; } + public long Identity2 { get; set; } } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithObjectProperty.cs b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithObjectProperty.cs index ff75eaf..e28139d 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithObjectProperty.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithObjectProperty.cs @@ -2,5 +2,5 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public class EntityWithObjectProperty { - public Object Value { get; set; } = null!; + public object Value { get; set; } = null!; } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithPrivateConstructor.cs b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithPrivateConstructor.cs index 2055c8d..3ded5a3 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithPrivateConstructor.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithPrivateConstructor.cs @@ -3,23 +3,23 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public record EntityWithPrivateConstructor : Entity { private EntityWithPrivateConstructor( - Byte[] bytesValue, - Boolean booleanValue, - Byte byteValue, - Char charValue, + byte[] bytesValue, + bool booleanValue, + byte byteValue, + char charValue, DateOnly dateOnlyValue, DateTime dateTimeValue, - Decimal decimalValue, - Double doubleValue, + decimal decimalValue, + double doubleValue, TestEnum enumValue, Guid guidValue, - Int64 id, - Int16 int16Value, - Int32 int32Value, - Int64 int64Value, - Boolean? nullableBooleanValue, - Single singleValue, - String stringValue, + long id, + short int16Value, + int int32Value, + long int64Value, + bool? nullableBooleanValue, + float singleValue, + string stringValue, TimeOnly timeOnlyValue, TimeSpan timeSpanValue ) diff --git a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithPublicConstructor.cs b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithPublicConstructor.cs index c2efb63..bcc330e 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithPublicConstructor.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithPublicConstructor.cs @@ -7,23 +7,23 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public record EntityWithPublicConstructor : Entity { public EntityWithPublicConstructor( - Byte[] bytesValue, - Boolean booleanValue, - Byte byteValue, - Char charValue, + byte[] bytesValue, + bool booleanValue, + byte byteValue, + char charValue, DateOnly dateOnlyValue, DateTime dateTimeValue, - Decimal decimalValue, - Double doubleValue, + decimal decimalValue, + double doubleValue, TestEnum enumValue, Guid guidValue, - Int64 id, - Int16 int16Value, - Int32 int32Value, - Int64 int64Value, - Boolean? nullableBooleanValue, - Single singleValue, - String stringValue, + long id, + short int16Value, + int int32Value, + long int64Value, + bool? nullableBooleanValue, + float singleValue, + string stringValue, TimeOnly timeOnlyValue, TimeSpan timeSpanValue ) diff --git a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithoutKeyProperty.cs b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithoutKeyProperty.cs index 89c4136..76d2347 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithoutKeyProperty.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithoutKeyProperty.cs @@ -2,5 +2,5 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public class EntityWithoutKeyProperty { - public Int32 Value { get; set; } + public int Value { get; set; } } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionA.cs b/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionA.cs index aa57321..3386734 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionA.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionA.cs @@ -6,18 +6,18 @@ public class FakeConnectionA : DbConnection { /// [AllowNull] - public override String ConnectionString { get; set; } + public override string ConnectionString { get; set; } /// - public override String Database => + public override string Database => null!; /// - public override String DataSource => + public override string DataSource => null!; /// - public override String ServerVersion => + public override string ServerVersion => null!; /// @@ -25,7 +25,7 @@ public class FakeConnectionA : DbConnection ConnectionState.Closed; /// - public override void ChangeDatabase(String databaseName) => + public override void ChangeDatabase(string databaseName) => throw new NotImplementedException(); /// diff --git a/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionB.cs b/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionB.cs index 03da059..245b249 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionB.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionB.cs @@ -6,18 +6,18 @@ public class FakeConnectionB : DbConnection { /// [AllowNull] - public override String ConnectionString { get; set; } + public override string ConnectionString { get; set; } /// - public override String Database => + public override string Database => null!; /// - public override String DataSource => + public override string DataSource => null!; /// - public override String ServerVersion => + public override string ServerVersion => null!; /// @@ -25,7 +25,7 @@ public class FakeConnectionB : DbConnection ConnectionState.Closed; /// - public override void ChangeDatabase(String databaseName) => + public override void ChangeDatabase(string databaseName) => throw new NotImplementedException(); /// diff --git a/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionC.cs b/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionC.cs index d2fecd9..c68c1c4 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionC.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionC.cs @@ -6,18 +6,18 @@ public class FakeConnectionC : FakeConnectionA { /// [AllowNull] - public override String ConnectionString { get; set; } + public override string ConnectionString { get; set; } /// - public override String Database => + public override string Database => null!; /// - public override String DataSource => + public override string DataSource => null!; /// - public override String ServerVersion => + public override string ServerVersion => null!; /// @@ -25,7 +25,7 @@ public class FakeConnectionC : FakeConnectionA ConnectionState.Closed; /// - public override void ChangeDatabase(String databaseName) => + public override void ChangeDatabase(string databaseName) => throw new NotImplementedException(); /// diff --git a/tests/DbConnectionPlus.UnitTests/TestData/Generate.cs b/tests/DbConnectionPlus.UnitTests/TestData/Generate.cs index 1697765..d7ab331 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/Generate.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/Generate.cs @@ -83,7 +83,7 @@ static Generate() fixture.Register(() => { // We limit to 3 fractional digits because not all database systems support a higher precision. - return (Single)Math.Round(faker.Random.Float(0, 999), 3); + return (float)Math.Round(faker.Random.Float(0, 999), 3); } ); fixture.Register(() => faker.Lorem.Sentence()); @@ -119,7 +119,7 @@ static Generate() /// Generates an ID. /// /// An ID. - public static Int64 Id() => + public static long Id() => Interlocked.Increment(ref entityId); /// @@ -130,7 +130,7 @@ public static Int64 Id() => /// If omitted a small random number () will be used. /// /// A list of IDs. - public static List Ids(Int32? numberOfIds = null) => + public static List Ids(int? numberOfIds = null) => [.. Enumerable.Range(0, numberOfIds ?? SmallNumber()).Select(_ => Interlocked.Increment(ref entityId))]; /// @@ -141,7 +141,7 @@ public static List Ids(Int32? numberOfIds = null) => /// /// A list of objects containing the same data as . /// - public static List MapTo(IEnumerable objects) => + public static List MapTo(IEnumerable objects) => objects.Adapt>(); /// @@ -152,7 +152,7 @@ public static List MapTo(IEnumerable objects) => /// /// An instance of containing the same data as . /// - public static TTarget MapTo(Object obj) => + public static TTarget MapTo(object obj) => obj.Adapt(); /// @@ -164,7 +164,7 @@ public static TTarget MapTo(Object obj) => /// If omitted a small random number () will be used. /// /// A list of instances of the type populated with test data. - public static List Multiple(Int32? numberOfObjects = null) + public static List Multiple(int? numberOfObjects = null) { fixture.RepeatCount = numberOfObjects ?? SmallNumber(); return fixture.Create>(); @@ -183,7 +183,7 @@ public static List Multiple(Int32? numberOfObjects = null) /// A list of random values of the type and values. /// The list is guaranteed to have at least 50% of its values set to . /// - public static List MultipleNullable(Int32? numberOfValues = null) + public static List MultipleNullable(int? numberOfValues = null) where T : struct { fixture.RepeatCount = numberOfValues ?? SmallNumber(); @@ -212,24 +212,24 @@ public static List Multiple(Int32? numberOfObjects = null) /// or TimeSpan. /// /// A random scalar value. - public static Object ScalarValue() => + public static object ScalarValue() => faker.Random.Int(0, 14) switch { - 0 => fixture.Create(), - 1 => fixture.Create(), - 2 => fixture.Create(), + 0 => fixture.Create(), + 1 => fixture.Create(), + 2 => fixture.Create(), 3 => fixture.Create(), 4 => fixture.Create(), - 5 => fixture.Create(), - 6 => fixture.Create(), + 5 => fixture.Create(), + 6 => fixture.Create(), 7 => fixture.Create(), - 8 => fixture.Create(), - 9 => fixture.Create(), - 10 => fixture.Create(), - 11 => fixture.Create(), - 12 => fixture.Create(), + 8 => fixture.Create(), + 9 => fixture.Create(), + 10 => fixture.Create(), + 11 => fixture.Create(), + 12 => fixture.Create(), 13 => fixture.Create(), - _ => fixture.Create() + _ => fixture.Create() }; /// @@ -247,7 +247,7 @@ public static T Single() /// Generates a random number between 5 and 15. /// /// A random number between 5 and 15. - public static Int32 SmallNumber() => + public static int SmallNumber() => faker.Random.Int(5, 15); /// @@ -316,11 +316,11 @@ private static void CopyKeysAndConcurrencyTokens(T sourceEntity, T targetEnti /// We only use alphabetic characters for Char generation to avoid issues with databases that do not support /// certain characters. /// - private static readonly Char[] characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray(); + private static readonly char[] characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray(); private static readonly Faker faker; private static readonly Fixture fixture; - private static Int64 entityId = 1; + private static long entityId = 1; /// /// An AutoFixture customization that excludes properties that are ignored in the entity model from being populated @@ -333,7 +333,7 @@ public void Customize(IFixture fixture) => private class OmitNotMappedPropertySpecimenBuilder : ISpecimenBuilder { - public Object Create(Object request, ISpecimenContext context) + public object Create(object request, ISpecimenContext context) { if (request is PropertyInfo propertyInfo) { diff --git a/tests/DbConnectionPlus.UnitTests/TestData/Item.cs b/tests/DbConnectionPlus.UnitTests/TestData/Item.cs index 798dbc0..98eaa0a 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/Item.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/Item.cs @@ -1,3 +1,3 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; -public record Item(Int64 Id, String Name, TestEnum Enum); +public record Item(long Id, string Name, TestEnum Enum); diff --git a/tests/DbConnectionPlus.UnitTests/TestData/ItemWithConstructor.cs b/tests/DbConnectionPlus.UnitTests/TestData/ItemWithConstructor.cs index 84f0562..5d7a968 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/ItemWithConstructor.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/ItemWithConstructor.cs @@ -6,14 +6,14 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public class ItemWithConstructor { - public ItemWithConstructor(Int16 a, Int32 b, Int64 c) + public ItemWithConstructor(short a, int b, long c) { this.A = a; this.B = b; this.C = c; } - public Int16 A { get; init; } - public Int32 B { get; init; } - public Int64 C { get; init; } + public short A { get; init; } + public int B { get; init; } + public long C { get; init; } } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/ItemWithPrivateConstructor.cs b/tests/DbConnectionPlus.UnitTests/TestData/ItemWithPrivateConstructor.cs index e50c677..22e7ca7 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/ItemWithPrivateConstructor.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/ItemWithPrivateConstructor.cs @@ -2,14 +2,14 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public sealed class ItemWithPrivateConstructor { - private ItemWithPrivateConstructor(Int16 a, Int32 b, Int64 c) + private ItemWithPrivateConstructor(short a, int b, long c) { this.A = a; this.B = b; this.C = c; } - public Int16 A { get; init; } - public Int32 B { get; init; } - public Int64 C { get; init; } + public short A { get; init; } + public int B { get; init; } + public long C { get; init; } } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/MappingTestEntity.cs b/tests/DbConnectionPlus.UnitTests/TestData/MappingTestEntity.cs index 5712727..b0a00ed 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/MappingTestEntity.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/MappingTestEntity.cs @@ -2,13 +2,13 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public record MappingTestEntity { - public Byte[]? ConcurrencyToken { get; set; } + public byte[]? ConcurrencyToken { get; set; } [Key] - public Int64 Key1 { get; set; } + public long Key1 { get; set; } [Key] - public Int64 Key2 { get; set; } + public long Key2 { get; set; } - public Int32 Value { get; set; } + public int Value { get; set; } } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/MappingTestEntityAttributes.cs b/tests/DbConnectionPlus.UnitTests/TestData/MappingTestEntityAttributes.cs index 170e495..fddf169 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/MappingTestEntityAttributes.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/MappingTestEntityAttributes.cs @@ -7,31 +7,31 @@ public record MappingTestEntityAttributes { [Column("Computed")] [DatabaseGenerated(DatabaseGeneratedOption.Computed)] - public Int32 Computed_ { get; set; } + public int Computed_ { get; set; } [Column("ConcurrencyToken")] [ConcurrencyCheck] - public Byte[]? ConcurrencyToken_ { get; set; } + public byte[]? ConcurrencyToken_ { get; set; } [Column("Identity")] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public Int32 Identity_ { get; set; } + public int Identity_ { get; set; } [Key] [Column("Key1")] - public Int64 Key1_ { get; set; } + public long Key1_ { get; set; } [Key] [Column("Key2")] - public Int64 Key2_ { get; set; } + public long Key2_ { get; set; } [NotMapped] - public String? NotMapped { get; set; } + public string? NotMapped { get; set; } [Column("RowVersion")] [Timestamp] - public Byte[]? RowVersion_ { get; set; } + public byte[]? RowVersion_ { get; set; } [Column("Value")] - public Int32 Value_ { get; set; } + public int Value_ { get; set; } } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/MappingTestEntityFluentApi.cs b/tests/DbConnectionPlus.UnitTests/TestData/MappingTestEntityFluentApi.cs index 7e86898..446d952 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/MappingTestEntityFluentApi.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/MappingTestEntityFluentApi.cs @@ -4,14 +4,14 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public record MappingTestEntityFluentApi { - public Int32 Computed_ { get; set; } - public Byte[]? ConcurrencyToken_ { get; set; } - public Int32 Identity_ { get; set; } - public Int64 Key1_ { get; set; } - public Int64 Key2_ { get; set; } - public String? NotMapped { get; set; } - public Byte[]? RowVersion_ { get; set; } - public Int32 Value_ { get; set; } + public int Computed_ { get; set; } + public byte[]? ConcurrencyToken_ { get; set; } + public int Identity_ { get; set; } + public long Key1_ { get; set; } + public long Key2_ { get; set; } + public string? NotMapped { get; set; } + public byte[]? RowVersion_ { get; set; } + public int Value_ { get; set; } /// /// Configures the mapping for this entity using the Fluent API. diff --git a/tests/DbConnectionPlus.UnitTests/TestData/NotAValueTuple.cs b/tests/DbConnectionPlus.UnitTests/TestData/NotAValueTuple.cs index a223a4e..6c69fea 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/NotAValueTuple.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/NotAValueTuple.cs @@ -6,18 +6,18 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public struct NotAValueTuple : IStructuralEquatable, IStructuralComparable, IComparable { /// - public Int32 CompareTo(Object? other, IComparer comparer) => + public int CompareTo(object? other, IComparer comparer) => throw new NotImplementedException(); /// - public Int32 CompareTo(Object? obj) => + public int CompareTo(object? obj) => throw new NotImplementedException(); /// - public Boolean Equals(Object? other, IEqualityComparer comparer) => + public bool Equals(object? other, IEqualityComparer comparer) => throw new NotImplementedException(); /// - public Int32 GetHashCode(IEqualityComparer comparer) => + public int GetHashCode(IEqualityComparer comparer) => throw new NotImplementedException(); } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/TemporaryTableTestItem.cs b/tests/DbConnectionPlus.UnitTests/TestData/TemporaryTableTestItem.cs index 511e5db..d4f35be 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/TemporaryTableTestItem.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/TemporaryTableTestItem.cs @@ -2,19 +2,19 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public class TemporaryTableTestItem { - public Boolean Boolean { get; set; } - public Byte[] Bytes { get; set; } = null!; - public Char Char { get; set; } + public bool Boolean { get; set; } + public byte[] Bytes { get; set; } = null!; + public char Char { get; set; } public DateOnly DateOnly { get; set; } public DateTime DateTime { get; set; } - public Decimal Decimal { get; set; } - public Double Double { get; set; } + public decimal Decimal { get; set; } + public double Double { get; set; } public Guid Guid { get; set; } - public Int16 Int16 { get; set; } - public Int32 Int32 { get; set; } - public Int64 Int64 { get; set; } - public Single Single { get; set; } - public String String { get; set; } = null!; + public short Int16 { get; set; } + public int Int32 { get; set; } + public long Int64 { get; set; } + public float Single { get; set; } + public string String { get; set; } = null!; public TimeOnly TimeOnly { get; set; } public TimeSpan TimeSpan { get; set; } } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/TemporaryTableTestItemWithNullableProperties.cs b/tests/DbConnectionPlus.UnitTests/TestData/TemporaryTableTestItemWithNullableProperties.cs index 4d495e5..c77225c 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/TemporaryTableTestItemWithNullableProperties.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/TemporaryTableTestItemWithNullableProperties.cs @@ -2,19 +2,19 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public class TemporaryTableTestItemWithNullableProperties { - public Boolean? Boolean { get; set; } - public Byte[]? Bytes { get; set; } - public Char? Char { get; set; } + public bool? Boolean { get; set; } + public byte[]? Bytes { get; set; } + public char? Char { get; set; } public DateOnly? DateOnly { get; set; } public DateTime? DateTime { get; set; } - public Decimal? Decimal { get; set; } - public Double? Double { get; set; } + public decimal? Decimal { get; set; } + public double? Double { get; set; } public Guid? Guid { get; set; } - public Int16? Int16 { get; set; } - public Int32? Int32 { get; set; } - public Int64? Int64 { get; set; } - public Single? Single { get; set; } - public String? String { get; set; } + public short? Int16 { get; set; } + public int? Int32 { get; set; } + public long? Int64 { get; set; } + public float? Single { get; set; } + public string? String { get; set; } public TimeOnly? TimeOnly { get; set; } public TimeSpan? TimeSpan { get; set; } } diff --git a/tests/DbConnectionPlus.UnitTests/Trimming/ILLinkDescriptorsTests.cs b/tests/DbConnectionPlus.UnitTests/Trimming/ILLinkDescriptorsTests.cs index 706ca0e..56a4515 100644 --- a/tests/DbConnectionPlus.UnitTests/Trimming/ILLinkDescriptorsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Trimming/ILLinkDescriptorsTests.cs @@ -36,12 +36,12 @@ public void CoreAssembly_ShouldEmbedTheILLinkDescriptor() => [InlineData(6)] [InlineData(7)] [InlineData(8)] - public void ILLinkDescriptor_ShouldPreserveAllMembersOfEveryValueTupleArity(Int32 arity) + public void ILLinkDescriptor_ShouldPreserveAllMembersOfEveryValueTupleArity(int arity) { var preservedTypes = ReadDescriptor() .Descendants("type") - .Where(a => (String?)a.Attribute("preserve") == "all") - .Select(a => (String?)a.Attribute("fullname")) + .Where(a => (string?)a.Attribute("preserve") == "all") + .Select(a => (string?)a.Attribute("fullname")) .ToList(); preservedTypes @@ -56,5 +56,5 @@ private static XDocument ReadDescriptor() return XDocument.Load(stream); } - private const String ILLinkDescriptorsResourceName = "ILLink.Descriptors.xml"; + private const string ILLinkDescriptorsResourceName = "ILLink.Descriptors.xml"; } diff --git a/tests/DbConnectionPlus.UnitTests/UnitTestsBase.cs b/tests/DbConnectionPlus.UnitTests/UnitTestsBase.cs index 5b962ae..4ab4f0c 100644 --- a/tests/DbConnectionPlus.UnitTests/UnitTestsBase.cs +++ b/tests/DbConnectionPlus.UnitTests/UnitTestsBase.cs @@ -52,7 +52,7 @@ public UnitTestsBase() this.MockTemporaryTableBuilder.BuildTemporaryTable( Arg.Any(), Arg.Any(), - Arg.Any(), + Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any() @@ -61,7 +61,7 @@ public UnitTestsBase() this.MockTemporaryTableBuilder.BuildTemporaryTableAsync( Arg.Any(), Arg.Any(), - Arg.Any(), + Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any() @@ -71,21 +71,21 @@ public UnitTestsBase() this.MockDatabaseAdapter.TemporaryTableBuilder.Returns(this.MockTemporaryTableBuilder); - this.MockDatabaseAdapter.QuoteIdentifier(Arg.Any()) - .Returns(info => $"[{info.ArgAt(0)}]"); + this.MockDatabaseAdapter.QuoteIdentifier(Arg.Any()) + .Returns(info => $"[{info.ArgAt(0)}]"); - this.MockDatabaseAdapter.QuoteTemporaryTableName(Arg.Any(), this.MockDbConnection) - .Returns(info => $"[#{info.ArgAt(0)}]"); + this.MockDatabaseAdapter.QuoteTemporaryTableName(Arg.Any(), this.MockDbConnection) + .Returns(info => $"[#{info.ArgAt(0)}]"); - this.MockDatabaseAdapter.FormatParameterName(Arg.Any()) - .Returns(info => $"@{info.ArgAt(0)}"); + this.MockDatabaseAdapter.FormatParameterName(Arg.Any()) + .Returns(info => $"@{info.ArgAt(0)}"); this.MockDatabaseAdapter - .When(a => a.BindParameterValue(Arg.Any(), Arg.Any())) + .When(a => a.BindParameterValue(Arg.Any(), Arg.Any())) .Do(info => { var parameter = info.ArgAt(0); - var value = info.ArgAt(1); + var value = info.ArgAt(1); if (value is Enum enumValue) { From 3c4793070f06013f6bfe28cf1b921b464e845e45 Mon Sep 17 00:00:00 2001 From: David Liebeherr Date: Thu, 27 Aug 2026 06:57:09 +0200 Subject: [PATCH 03/12] style: convert eligible constructors to primary constructors `dotnet format style --diagnostics IDE0290`. Six sites. Carries one hand edit the fixer cannot do: it leaves the old `Initializes a new instance...` blocks behind after moving the parameter documentation to the type, and those 23 lines are removed here. Reproducing the commit therefore differs by exactly those lines. Part of #21 Co-Authored-By: Claude Opus 5 --- .../OracleEntityManipulator.cs | 12 +++------ .../PostgreSqlEntityManipulator.cs | 12 +++------ .../SqlServerEntityManipulator.cs | 12 +++------ .../SqliteEntityManipulator.cs | 12 +++------ src/DbConnectionPlus/Dynamic/DataRow.cs | 18 +++++-------- .../StatementMethodTestsBase.cs | 27 +++++++------------ 6 files changed, 27 insertions(+), 66 deletions(-) diff --git a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleEntityManipulator.cs index e64d83c..6bcefce 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleEntityManipulator.cs @@ -11,15 +11,9 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.Oracle; /// /// The entity manipulator for PostgreSQL. /// -internal class OracleEntityManipulator : IEntityManipulator +/// The database adapter to use to manipulate entities. +internal class OracleEntityManipulator(OracleDatabaseAdapter databaseAdapter) : IEntityManipulator { - /// - /// Initializes a new instance of the class. - /// - /// The database adapter to use to manipulate entities. - public OracleEntityManipulator(OracleDatabaseAdapter databaseAdapter) => - this.databaseAdapter = databaseAdapter; - /// public int DeleteEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity @@ -1217,7 +1211,7 @@ object entity } } - private readonly OracleDatabaseAdapter databaseAdapter; + private readonly OracleDatabaseAdapter databaseAdapter = databaseAdapter; private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); diff --git a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlEntityManipulator.cs index 06528d3..ecc21df 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlEntityManipulator.cs @@ -11,15 +11,9 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.PostgreSql; /// /// The entity manipulator for PostgreSQL. /// -internal class PostgreSqlEntityManipulator : IEntityManipulator +/// The database adapter to use to manipulate entities. +internal class PostgreSqlEntityManipulator(PostgreSqlDatabaseAdapter databaseAdapter) : IEntityManipulator { - /// - /// Initializes a new instance of the class. - /// - /// The database adapter to use to manipulate entities. - public PostgreSqlEntityManipulator(PostgreSqlDatabaseAdapter databaseAdapter) => - this.databaseAdapter = databaseAdapter; - /// public int DeleteEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity @@ -1197,7 +1191,7 @@ await reader.ReadAsync(cancellationToken).ConfigureAwait(false) } } - private readonly PostgreSqlDatabaseAdapter databaseAdapter; + private readonly PostgreSqlDatabaseAdapter databaseAdapter = databaseAdapter; private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); diff --git a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerEntityManipulator.cs index 7a0e0f2..ef9252b 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerEntityManipulator.cs @@ -11,15 +11,9 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.SqlServer; /// /// The entity manipulator for SQL Server. /// -internal class SqlServerEntityManipulator : IEntityManipulator +/// The database adapter to use to manipulate entities. +internal class SqlServerEntityManipulator(SqlServerDatabaseAdapter databaseAdapter) : IEntityManipulator { - /// - /// Initializes a new instance of the class. - /// - /// The database adapter to use to manipulate entities. - public SqlServerEntityManipulator(SqlServerDatabaseAdapter databaseAdapter) => - this.databaseAdapter = databaseAdapter; - /// public int DeleteEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity @@ -1197,7 +1191,7 @@ await reader.ReadAsync(cancellationToken).ConfigureAwait(false) } } - private readonly SqlServerDatabaseAdapter databaseAdapter; + private readonly SqlServerDatabaseAdapter databaseAdapter = databaseAdapter; private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); diff --git a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteEntityManipulator.cs index 8a733b6..cdd56f8 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteEntityManipulator.cs @@ -11,15 +11,9 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.Sqlite; /// /// The entity manipulator for SQLite. /// -internal class SqliteEntityManipulator : IEntityManipulator +/// The database adapter to use to manipulate entities. +internal class SqliteEntityManipulator(SqliteDatabaseAdapter databaseAdapter) : IEntityManipulator { - /// - /// Initializes a new instance of the class. - /// - /// The database adapter to use to manipulate entities. - public SqliteEntityManipulator(SqliteDatabaseAdapter databaseAdapter) => - this.databaseAdapter = databaseAdapter; - /// public int DeleteEntities< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity @@ -1287,7 +1281,7 @@ await reader.ReadAsync(cancellationToken).ConfigureAwait(false) } } - private readonly SqliteDatabaseAdapter databaseAdapter; + private readonly SqliteDatabaseAdapter databaseAdapter = databaseAdapter; private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); diff --git a/src/DbConnectionPlus/Dynamic/DataRow.cs b/src/DbConnectionPlus/Dynamic/DataRow.cs index f95828b..2f78f93 100644 --- a/src/DbConnectionPlus/Dynamic/DataRow.cs +++ b/src/DbConnectionPlus/Dynamic/DataRow.cs @@ -39,20 +39,14 @@ namespace RentADeveloper.DbConnectionPlus.Dynamic; /// var name = product.Name; /// /// +/// +/// The columns of the data row. +/// The keys are expected to be the column names, and the values are expected to be the corresponding column values. +/// #pragma warning disable CA1710 -public class DataRow : IDictionary, IDynamicMetaObjectProvider +public class DataRow(IDictionary columns) : IDictionary, IDynamicMetaObjectProvider #pragma warning restore CA1710 { - /// - /// Initializes a new instance of the class. - /// - /// - /// The columns of the data row. - /// The keys are expected to be the column names, and the values are expected to be the corresponding column values. - /// - public DataRow(IDictionary columns) => - this.columns = columns; - /// public int Count => this.columns.Count; @@ -145,7 +139,7 @@ IEnumerator IEnumerable.GetEnumerator() => private static readonly Func writeColumn = static (row, columnName, value) => row[columnName] = value; - private readonly IDictionary columns; + private readonly IDictionary columns = columns; /// /// Binds member access on a to the columns of the row, so that row.Id resolves to diff --git a/tests/DbConnectionPlus.UnitTests/StatementMethodTestsBase.cs b/tests/DbConnectionPlus.UnitTests/StatementMethodTestsBase.cs index 6280b3b..491def1 100644 --- a/tests/DbConnectionPlus.UnitTests/StatementMethodTestsBase.cs +++ b/tests/DbConnectionPlus.UnitTests/StatementMethodTestsBase.cs @@ -7,24 +7,15 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; /// /// Base class for unit tests of methods that execute SQL statements. /// -public abstract class StatementMethodTestsBase : UnitTestsBase -{ - /// - /// Initializes a new instance of the class. - /// - /// The asynchronous version of the statement method to test. - /// The synchronous version of the statement method to test. - protected StatementMethodTestsBase( - Func +/// The asynchronous version of the statement method to test. +/// The synchronous version of the statement method to test. +public abstract class StatementMethodTestsBase( + Func asyncTestMethod, - Action + Action syncTestMethod - ) - { - this.asyncTestMethod = asyncTestMethod; - this.syncTestMethod = syncTestMethod; - } - + ) : UnitTestsBase +{ [Fact] public async Task AsyncMethod_ShouldUseCommandTimeout() { @@ -143,9 +134,9 @@ public void SyncMethod_ShouldUseTransaction() private readonly Func - asyncTestMethod; + asyncTestMethod = asyncTestMethod; private readonly Action - syncTestMethod; + syncTestMethod = syncTestMethod; } From 8ee77bf5ba2380f91d583a645757db840c6b20f0 Mon Sep 17 00:00:00 2001 From: David Liebeherr Date: Thu, 27 Aug 2026 06:57:23 +0200 Subject: [PATCH 04/12] build: hold every project to the style gate, and add CSharpier EnforceCodeStyleInBuild and TreatWarningsAsErrors move to the root Directory.Build.props, so tests/ and benchmarks/ are held to the same style as the libraries. The CA quality rules stay in src/ only - CA1707 alone fires 2100 times on the Method_ShouldDoSomething naming the test suite is built around. CSharpier becomes the formatter: pinned in .config/dotnet-tools.json, with .csharpierignore for the hand-maintained XML. IDE0055 goes off, because whitespace is now CSharpier's and the two disagree. The print width comes from max_line_length in .editorconfig, so it has one source of truth. Part of #21 Co-Authored-By: Claude Opus 5 --- .config/dotnet-tools.json | 9 +++++++- .csharpierignore | 18 +++++++++++++++ .editorconfig | 9 ++++++-- Directory.Build.props | 22 +++++++++++++++++-- src/Directory.Build.props | 16 +++++++++----- .../Converters/ValueConverterTests.cs | 14 ++++-------- 6 files changed, 67 insertions(+), 21 deletions(-) create mode 100644 .csharpierignore diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index db0b903..76f6a45 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -8,6 +8,13 @@ "docfx" ], "rollForward": false + }, + "csharpier": { + "version": "1.3.0", + "commands": [ + "csharpier" + ], + "rollForward": false } } -} +} \ No newline at end of file diff --git a/.csharpierignore b/.csharpierignore new file mode 100644 index 0000000..048e2fe --- /dev/null +++ b/.csharpierignore @@ -0,0 +1,18 @@ +# CSharpier formats C# in this repository, and nothing else. +# +# Since version 1.0 it can also format XML, which here means the .csproj, .props, .targets, .slnx and +# .config files. Those are hand-maintained: they carry long explanatory comments, deliberate blank lines +# between the property groups, and one item per line. CSharpier's XML formatter reflows all of that - +# it splits short attribute lists across four lines each and re-indents elements without re-indenting +# the comment bodies inside them. .editorconfig already fixes their indentation, which is all they need. +# +# Build output and generated documentation are not listed: CSharpier honours .gitignore, and obj, bin, +# docs/api and docs/_site are all in there already. + +*.csproj +*.props +*.targets +*.slnx +*.config +*.xml +*.DotSettings diff --git a/.editorconfig b/.editorconfig index 8ab2675..8d003ae 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,11 +15,16 @@ indent_size = 4 insert_final_newline = true trim_trailing_whitespace = true -# MSBuild and project files are tab-indented, which is what is already in the repository. -[*.{csproj,props,targets,slnx,config,resx,DotSettings}] +# MSBuild and ReSharper settings files are tab-indented, which is what is already in the repository. +[*.{csproj,props,targets,DotSettings}] indent_style = tab tab_width = 4 +# The solution file, the NuGet configs and the trimmer descriptor use two spaces, also matching what is +# already there. +[*.{slnx,config,xml}] +indent_size = 2 + [*.{json,yml,yaml}] indent_size = 2 diff --git a/Directory.Build.props b/Directory.Build.props index 5260d22..5c74f7c 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -23,11 +23,29 @@ true + + + True + true + + all diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 7429cb4..32008c3 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -4,11 +4,12 @@ Shared build properties for the shipping libraries. The repository-root Directory.Build.props carries what every project needs (authorship, language - settings, the style analyzers). MSBuild uses the nearest Directory.Build.props and stops, so this file - imports it explicitly - without that import, the projects under src/ would silently lose all of it. + settings, the style analyzers, and the style gate itself - EnforceCodeStyleInBuild with + TreatWarningsAsErrors). MSBuild uses the nearest Directory.Build.props and stops, so this file imports + it explicitly - without that import, the projects under src/ would silently lose all of it. - What lives here is what only a shipping, packable library needs: multi-targeting, the AOT and public-API - analyzers, warnings-as-errors, and the NuGet package metadata. Per-project identity - AssemblyName, + What lives here is what only a shipping, packable library needs: multi-targeting, the AOT, CA and + public-API analyzers, and the NuGet package metadata. Per-project identity - AssemblyName, AssemblyTitle, RootNamespace, PackageId, Description, PackageTags - stays in each .csproj. --> @@ -44,10 +45,13 @@ + latest-all True - True - true diff --git a/tests/DbConnectionPlus.UnitTests/Converters/ValueConverterTests.cs b/tests/DbConnectionPlus.UnitTests/Converters/ValueConverterTests.cs index d9e54f6..8a43d95 100644 --- a/tests/DbConnectionPlus.UnitTests/Converters/ValueConverterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Converters/ValueConverterTests.cs @@ -689,14 +689,8 @@ object ExpectedTargetValue // @formatter:off - return new List<( - Type SourceType, - Type TargetType, - bool ExpectedCanConvert, - object? SourceValue, - object? ExpectedTargetValue - )> - { + return + [ (typeof(bool), typeof(bool), true, true, true), (typeof(bool), typeof(byte), true, true, (byte)1), (typeof(bool), typeof(decimal), true, true, (decimal)1), @@ -963,8 +957,8 @@ object ExpectedTargetValue (typeof(DateOnly), typeof(DateTime), false, dateOnlyValue, null), (typeof(TimeOnly), typeof(TimeSpan), false, timeOnlyValue, null), (typeof(DateOnly), typeof(Guid), false, dateOnlyValue, null), - (typeof(TimeOnly), typeof(Guid), false, timeOnlyValue, null) - }; + (typeof(TimeOnly), typeof(Guid), false, timeOnlyValue, null), + ]; // @formatter:on } From f80b2f75fa4a8331c1b63aef1686144560d1e904 Mon Sep 17 00:00:00 2001 From: David Liebeherr Date: Sun, 23 Aug 2026 03:50:23 +0200 Subject: [PATCH 05/12] style: reformat every C# file with CSharpier Mechanical. Applied with: dotnet csharpier format . 230 files. From here on nobody places a line break by hand: CSharpier reprints the file and the result is the same whoever - or whatever - wrote the code. Two things came through untouched, both worth knowing: - The 280-line conversion table in ValueConverterTests marked `@formatter:off`. Every row already fits inside 120 characters, so CSharpier leaves it exactly as it is and needs no csharpier-ignore directives. - Comment text. CSharpier does not rewrap the inside of a comment, so the XML documentation across the shipping libraries is unchanged. Verified after the reformat: Release build clean, 0 warnings, and the full test suite green - 11005 passed, 0 failed, integration tests included. This commit is listed in .git-blame-ignore-revs. Part of #21 Co-Authored-By: Claude Opus 5 --- .../AotJobFilter.cs | 6 +- .../Benchmarks.DeleteEntities.cs | 13 +- .../Benchmarks.DeleteEntity.cs | 20 +- .../Benchmarks.ExecuteNonQuery.cs | 16 +- .../Benchmarks.ExecuteReader.cs | 20 +- .../Benchmarks.ExecuteScalar.cs | 20 +- .../Benchmarks.Exists.cs | 26 +- .../Benchmarks.InsertEntities.cs | 93 +- .../Benchmarks.InsertEntity.cs | 25 +- .../Benchmarks.Parameter.cs | 44 +- .../Benchmarks.Query_Dynamic.cs | 35 +- .../Benchmarks.Query_Entities.cs | 16 +- .../Benchmarks.Query_Scalars.cs | 26 +- .../Benchmarks.Query_ValueTuples.cs | 44 +- ...enchmarks.TemporaryTable_ComplexObjects.cs | 126 +- .../Benchmarks.TemporaryTable_ScalarValues.cs | 36 +- .../Benchmarks.UpdateEntities.cs | 52 +- .../Benchmarks.UpdateEntity.cs | 56 +- .../DbConnectionPlus.Benchmarks/Benchmarks.cs | 13 +- .../BenchmarksConfig.cs | 4 +- .../BenchmarksOrderer.cs | 16 +- .../DbConnectionPlus.Benchmarks/Program.cs | 5 +- .../TestData/Generate.cs | 52 +- .../TestData/TestEnum.cs | 2 +- .../MySqlConfigurationExtensions.cs | 1 + .../MySqlDatabaseAdapter.cs | 38 +- .../MySqlEntityManipulator.cs | 215 +-- .../MySqlTemporaryTableBuilder.cs | 49 +- .../OracleConfigurationExtensions.cs | 1 + .../OracleDatabaseAdapter.cs | 54 +- .../OracleEntityManipulator.cs | 195 +-- .../OracleTemporaryTableBuilder.cs | 62 +- .../PostgreSqlConfigurationExtensions.cs | 1 + .../PostgreSqlDatabaseAdapter.cs | 55 +- .../PostgreSqlEntityManipulator.cs | 210 +-- .../PostgreSqlTemporaryTableBuilder.cs | 54 +- .../SqlServerConfigurationExtensions.cs | 1 + .../SqlServerDatabaseAdapter.cs | 44 +- .../SqlServerEntityManipulator.cs | 210 +-- .../SqlServerTemporaryTableBuilder.cs | 62 +- .../SqliteConfigurationExtensions.cs | 1 + .../SqliteDatabaseAdapter.cs | 39 +- .../SqliteEntityManipulator.cs | 212 +-- .../SqliteTemporaryTableBuilder.cs | 61 +- .../DbConnectionPlusConfiguration.cs | 14 +- .../Configuration/EntityPropertyBuilder.cs | 13 +- .../Configuration/EntityTypeBuilder.cs | 18 +- .../Converters/EnumConverter.cs | 82 +- .../Converters/EnumSerializer.cs | 9 +- .../Converters/ValueConverter.cs | 121 +- .../DatabaseAdapters/IDatabaseAdapter.cs | 5 +- .../DatabaseAdapters/IEntityManipulator.cs | 66 +- .../ITemporaryTableBuilder.cs | 6 +- .../DbCommands/DbCommandBuilder.cs | 94 +- .../DbConnectionExtensions.Configuration.cs | 3 +- .../DbConnectionExtensions.DeleteEntities.cs | 31 +- .../DbConnectionExtensions.DeleteEntity.cs | 30 +- .../DbConnectionExtensions.ExecuteNonQuery.cs | 34 +- .../DbConnectionExtensions.ExecuteReader.cs | 38 +- .../DbConnectionExtensions.ExecuteScalar.cs | 52 +- .../DbConnectionExtensions.Exists.cs | 45 +- .../DbConnectionExtensions.InsertEntities.cs | 40 +- .../DbConnectionExtensions.InsertEntity.cs | 34 +- .../DbConnectionExtensions.Parameter.cs | 7 +- .../DbConnectionExtensions.Query.cs | 45 +- .../DbConnectionExtensions.QueryFirst.cs | 38 +- .../DbConnectionExtensions.QueryFirstOfT.cs | 112 +- ...onnectionExtensions.QueryFirstOrDefault.cs | 38 +- ...ectionExtensions.QueryFirstOrDefaultOfT.cs | 108 +- .../DbConnectionExtensions.QueryOfT.cs | 120 +- .../DbConnectionExtensions.QuerySingle.cs | 38 +- .../DbConnectionExtensions.QuerySingleOfT.cs | 109 +- ...nnectionExtensions.QuerySingleOrDefault.cs | 38 +- ...ctionExtensions.QuerySingleOrDefaultOfT.cs | 105 +- .../DbConnectionExtensions.TemporaryTable.cs | 16 +- .../DbConnectionExtensions.UpdateEntities.cs | 39 +- .../DbConnectionExtensions.UpdateEntity.cs | 30 +- src/DbConnectionPlus/Dynamic/DataRow.cs | 56 +- src/DbConnectionPlus/Entities/EntityHelper.cs | 127 +- src/DbConnectionPlus/EnumSerializationMode.cs | 2 +- .../DbUpdateConcurrencyException.cs | 18 +- .../Extensions/Int32Extensions.cs | 3 +- .../Extensions/ObjectExtensions.cs | 80 +- .../Extensions/TypeExtensions.cs | 4 +- src/DbConnectionPlus/Helpers/NameHelper.cs | 9 +- .../EntityMaterializerFactory.cs | 232 ++- .../MaterializerFactoryHelper.cs | 127 +- .../ValueTupleMaterializerFactory.cs | 161 +- .../CommandDisposingDataReaderDecorator.cs | 129 +- .../Readers/EnumerableReader.cs | 121 +- .../Readers/EnumerableReaderOptions.cs | 2 +- .../SqlStatements/InterpolatedParameter.cs | 3 +- .../SqlStatements/InterpolatedSqlStatement.cs | 40 +- .../InterpolatedSqlStatementDebugView.cs | 6 +- .../InterpolatedTemporaryTable.cs | 5 +- src/DbConnectionPlus/ThrowHelper.cs | 44 +- .../Assertions/EntityAssertions.cs | 61 +- .../EntityManipulator.DeleteEntitiesTests.cs | 204 ++- .../EntityManipulator.DeleteEntityTests.cs | 202 +-- .../EntityManipulator.InsertEntitiesTests.cs | 255 ++-- .../EntityManipulator.InsertEntityTests.cs | 148 +- .../EntityManipulator.UpdateEntitiesTests.cs | 454 +++--- .../EntityManipulator.UpdateEntityTests.cs | 332 ++--- .../MySql/MySqlDatabaseAdapterTests.cs | 3 +- .../Oracle/OracleDatabaseAdapterTests.cs | 21 +- .../PostgreSqlDatabaseAdapterTests.cs | 16 +- .../SqlServerDatabaseAdapterTests.cs | 15 +- .../Sqlite/SqliteDatabaseAdapterTests.cs | 3 +- .../TemporaryTableBuilderTests.cs | 264 ++-- .../DbCommands/DbCommandBuilderTests.cs | 183 +-- .../DbCommands/DbCommandDisposerTests.cs | 104 +- .../DbCommands/DbCommandHelperTests.cs | 50 +- ...nnectionExtensions.ExecuteNonQueryTests.cs | 179 ++- ...ConnectionExtensions.ExecuteReaderTests.cs | 171 +-- ...ConnectionExtensions.ExecuteScalarTests.cs | 314 ++-- .../DbConnectionExtensions.ExistsTests.cs | 166 ++- .../DbConnectionExtensions.ParameterTests.cs | 65 +- ...ConnectionExtensions.QueryFirstOfTTests.cs | 744 +++++---- ...nExtensions.QueryFirstOrDefaultOfTTests.cs | 818 +++++----- ...tionExtensions.QueryFirstOrDefaultTests.cs | 106 +- .../DbConnectionExtensions.QueryFirstTests.cs | 102 +- .../DbConnectionExtensions.QueryOfTTests.cs | 1327 +++++++++-------- ...onnectionExtensions.QuerySingleOfTTests.cs | 753 ++++++---- ...Extensions.QuerySingleOrDefaultOfTTests.cs | 833 ++++++----- ...ionExtensions.QuerySingleOrDefaultTests.cs | 117 +- ...DbConnectionExtensions.QuerySingleTests.cs | 108 +- .../DbConnectionExtensions.QueryTests.cs | 216 ++- ...onnectionExtensions.TemporaryTableTests.cs | 147 +- .../GlobalUsings.cs | 6 +- .../IntegrationTestsBase.cs | 101 +- ...ommandDisposingDataReaderDecoratorTests.cs | 67 +- .../Containers/MySqlContainerFixture.cs | 8 +- .../Containers/OracleContainerFixture.cs | 14 +- .../Containers/PostgreSqlContainerFixture.cs | 11 +- .../Containers/SqlServerContainerFixture.cs | 11 +- .../Containers/TestDatabaseContainer.cs | 9 +- .../TestDatabaseContainerCleanup.cs | 6 +- .../Containers/TestDatabaseContainers.cs | 24 +- .../TestDatabase/MySqlTestDatabaseProvider.cs | 29 +- .../OracleTestDatabaseProvider.cs | 24 +- .../PostgreSqlTestDatabaseProvider.cs | 40 +- .../SQLiteTestDatabaseProvider.cs | 47 +- .../SqlServerTestDatabaseProvider.cs | 45 +- .../TestDatabase/TestDatabaseFixture.cs | 6 +- .../Assertions/AssertionsExtensions.cs | 3 +- .../Assertions/DecoratorAssertions.cs | 26 +- .../DbConnectionPlusConfigurationTests.cs | 207 ++- .../EntityPropertyBuilderTests.cs | 94 +- .../Configuration/EntityTypeBuilderTests.cs | 50 +- .../Converters/EnumConverterTests.cs | 292 ++-- .../Converters/EnumSerializerTests.cs | 7 +- .../Converters/ValueConverterTests.cs | 685 ++++++--- .../MySqlConfigurationExtensionsTests.cs | 3 +- .../MySql/MySqlDatabaseAdapterTests.cs | 74 +- .../MySql/MySqlTemporaryTableBuilderTests.cs | 24 +- .../OracleConfigurationExtensionsTests.cs | 2 +- .../Oracle/OracleDatabaseAdapterTests.cs | 133 +- .../OracleTemporaryTableBuilderTests.cs | 58 +- .../PostgreSqlConfigurationExtensionsTests.cs | 2 +- .../PostgreSqlDatabaseAdapterTests.cs | 81 +- .../PostgreSqlTemporaryTableBuilderTests.cs | 24 +- .../SqlServerDatabaseAdapterTests.cs | 71 +- .../SqlServerTemporaryTableBuilderTests.cs | 24 +- .../SqliteConfigurationExtensionsTests.cs | 2 +- .../SqliteConfigurationExtensionsTests.cs | 2 +- .../Sqlite/SqliteDatabaseAdapterTests.cs | 74 +- .../SqliteTemporaryTableBuilderTests.cs | 24 +- .../TemporaryTableDisposerTests.cs | 4 +- .../DbCommands/DbCommandBuilderTests.cs | 452 +++--- .../DbCommands/DbCommandDisposerTests.cs | 39 +- .../DbCommands/DbCommandHelperTests.cs | 12 +- ...ConnectionExtensions.ConfigurationTests.cs | 180 +-- ...onnectionExtensions.DeleteEntitiesTests.cs | 47 +- ...bConnectionExtensions.DeleteEntityTests.cs | 47 +- ...nnectionExtensions.ExecuteNonQueryTests.cs | 35 +- ...ConnectionExtensions.ExecuteReaderTests.cs | 49 +- ...ConnectionExtensions.ExecuteScalarTests.cs | 35 +- .../DbConnectionExtensions.ExistsTests.cs | 35 +- ...onnectionExtensions.InsertEntitiesTests.cs | 47 +- ...bConnectionExtensions.InsertEntityTests.cs | 47 +- .../DbConnectionExtensions.ParameterTests.cs | 29 +- ...ConnectionExtensions.QueryFirstOfTTests.cs | 38 +- ...nExtensions.QueryFirstOrDefaultOfTTests.cs | 30 +- ...tionExtensions.QueryFirstOrDefaultTests.cs | 38 +- .../DbConnectionExtensions.QueryFirstTests.cs | 38 +- .../DbConnectionExtensions.QueryOfTTests.cs | 42 +- ...onnectionExtensions.QuerySingleOfTTests.cs | 38 +- ...Extensions.QuerySingleOrDefaultOfTTests.cs | 30 +- ...ionExtensions.QuerySingleOrDefaultTests.cs | 38 +- ...DbConnectionExtensions.QuerySingleTests.cs | 38 +- .../DbConnectionExtensions.QueryTests.cs | 43 +- ...onnectionExtensions.TemporaryTableTests.cs | 45 +- ...onnectionExtensions.UpdateEntitiesTests.cs | 47 +- ...bConnectionExtensions.UpdateEntityTests.cs | 47 +- .../Dynamic/DataRowTests.cs | 98 +- .../Entities/EntityHelperTests.cs | 381 +++-- .../Extensions/DbDataReaderExtensionsTests.cs | 6 +- .../Extensions/Int32ExtensionsTests.cs | 3 +- .../Extensions/ObjectExtensionsTests.cs | 145 +- .../Extensions/TypeExtensionsTests.cs | 24 +- .../GlobalUsings.cs | 6 +- .../Helpers/NameHelperTests.cs | 4 +- .../Materializers/DataRowMaterializerTests.cs | 28 +- .../EntityMaterializerFactoryTests.cs | 348 ++--- .../MaterializerFactoryHelperTests.cs | 165 +- .../ValueTupleMaterializerFactoryTests.cs | 433 +++--- .../Mocks/MockDbParameterCollection.cs | 12 +- ...ommandDisposingDataReaderDecoratorTests.cs | 15 +- .../Readers/EnumerableReaderOptionsTests.cs | 87 +- .../Readers/EnumerableReaderTests.cs | 150 +- .../InterpolatedSqlStatementTests.cs | 452 +++--- .../StatementMethodTestsBase.cs | 102 +- ...tityWithPrivateParameterlessConstructor.cs | 4 +- .../TestData/FakeConnectionA.cs | 24 +- .../TestData/FakeConnectionB.cs | 24 +- .../TestData/FakeConnectionC.cs | 24 +- .../TestData/Generate.cs | 135 +- ...ItemWithPrivateParameterlessConstructor.cs | 4 +- .../TestData/MappingTestEntityFluentApi.cs | 62 +- .../TestData/NotAValueTuple.cs | 12 +- .../TestData/TestEnum.cs | 2 +- .../Trimming/ILLinkDescriptorsTests.cs | 14 +- .../UnitTestsBase.cs | 107 +- .../AllAdaptersConsumer/GlobalUsings.cs | 2 +- .../AllAdaptersConsumer/Program.cs | 10 +- .../AotConsumer/GlobalUsings.cs | 2 +- .../package-consumption/AotConsumer/Model.cs | 10 +- .../AotConsumer/Program.cs | 5 +- .../AotConsumer/SmokeCases.cs | 123 +- tests/package-consumption/Check.cs | 5 +- 230 files changed, 9590 insertions(+), 10977 deletions(-) diff --git a/benchmarks/DbConnectionPlus.Benchmarks/AotJobFilter.cs b/benchmarks/DbConnectionPlus.Benchmarks/AotJobFilter.cs index 62008b1..c834e62 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/AotJobFilter.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/AotJobFilter.cs @@ -19,9 +19,7 @@ public bool Predicate(BenchmarkCase benchmarkCase) var benchmarkName = benchmarkCase.Descriptor.WorkloadMethod.Name; var isAotOnlyBenchmark = benchmarkName.EndsWith(AotOnlyBenchmarkSuffix, StringComparison.Ordinal); - return isAotJob - ? AotJobBenchmarks.Contains(benchmarkName) - : !isAotOnlyBenchmark; + return isAotJob ? AotJobBenchmarks.Contains(benchmarkName) : !isAotOnlyBenchmark; } // TemporaryTable_ComplexObjects is here because it ends in a Query over the temporary @@ -39,7 +37,7 @@ public bool Predicate(BenchmarkCase benchmarkCase) nameof(Benchmarks.Query_ValueTuples_Command), nameof(Benchmarks.Query_ValueTuples_DbConnectionPlus), nameof(Benchmarks.TemporaryTable_ComplexObjects_Command), - nameof(Benchmarks.TemporaryTable_ComplexObjects_DbConnectionPlus) + nameof(Benchmarks.TemporaryTable_ComplexObjects_DbConnectionPlus), ]; // Marks a benchmark as Native AOT only, so that it is kept out of the JIT job. diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntities.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntities.cs index bfbf086..220f978 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntities.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntities.cs @@ -8,22 +8,19 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { [GlobalCleanup( - Targets = - [ + Targets = [ nameof(DeleteEntities_Command), nameof(DeleteEntities_Dapper), - nameof(DeleteEntities_DbConnectionPlus) + nameof(DeleteEntities_DbConnectionPlus), ] )] - public void DeleteEntities__Cleanup() => - this.connection.Dispose(); + public void DeleteEntities__Cleanup() => this.connection.Dispose(); [GlobalSetup( - Targets = - [ + Targets = [ nameof(DeleteEntities_Command), nameof(DeleteEntities_Dapper), - nameof(DeleteEntities_DbConnectionPlus) + nameof(DeleteEntities_DbConnectionPlus), ] )] public void DeleteEntities__Setup() diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntity.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntity.cs index eb15846..3b33f48 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntity.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntity.cs @@ -8,26 +8,14 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { [GlobalCleanup( - Targets = - [ - nameof(DeleteEntity_Command), - nameof(DeleteEntity_Dapper), - nameof(DeleteEntity_DbConnectionPlus) - ] + Targets = [nameof(DeleteEntity_Command), nameof(DeleteEntity_Dapper), nameof(DeleteEntity_DbConnectionPlus)] )] - public void DeleteEntity__Cleanup() => - this.connection.Dispose(); + public void DeleteEntity__Cleanup() => this.connection.Dispose(); [GlobalSetup( - Targets = - [ - nameof(DeleteEntity_Command), - nameof(DeleteEntity_Dapper), - nameof(DeleteEntity_DbConnectionPlus) - ] + Targets = [nameof(DeleteEntity_Command), nameof(DeleteEntity_Dapper), nameof(DeleteEntity_DbConnectionPlus)] )] - public void DeleteEntity__Setup() => - this.SetupDatabase(DeleteEntity_OperationsPerInvoke); + public void DeleteEntity__Setup() => this.SetupDatabase(DeleteEntity_OperationsPerInvoke); [Benchmark(Baseline = true, OperationsPerInvoke = DeleteEntity_OperationsPerInvoke)] [BenchmarkCategory(DeleteEntity_Category)] diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteNonQuery.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteNonQuery.cs index ce05cc6..e3d3498 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteNonQuery.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteNonQuery.cs @@ -8,26 +8,22 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { [GlobalCleanup( - Targets = - [ + Targets = [ nameof(ExecuteNonQuery_Command), nameof(ExecuteNonQuery_Dapper), - nameof(ExecuteNonQuery_DbConnectionPlus) + nameof(ExecuteNonQuery_DbConnectionPlus), ] )] - public void ExecuteNonQuery__Cleanup() => - this.connection.Dispose(); + public void ExecuteNonQuery__Cleanup() => this.connection.Dispose(); [GlobalSetup( - Targets = - [ + Targets = [ nameof(ExecuteNonQuery_Command), nameof(ExecuteNonQuery_Dapper), - nameof(ExecuteNonQuery_DbConnectionPlus) + nameof(ExecuteNonQuery_DbConnectionPlus), ] )] - public void ExecuteNonQuery__Setup() => - this.SetupDatabase(0); + public void ExecuteNonQuery__Setup() => this.SetupDatabase(0); [Benchmark(Baseline = true)] [BenchmarkCategory(ExecuteNonQuery_Category)] diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteReader.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteReader.cs index dae7d43..4553d13 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteReader.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteReader.cs @@ -8,26 +8,14 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { [GlobalCleanup( - Targets = - [ - nameof(ExecuteReader_Command), - nameof(ExecuteReader_Dapper), - nameof(ExecuteReader_DbConnectionPlus) - ] + Targets = [nameof(ExecuteReader_Command), nameof(ExecuteReader_Dapper), nameof(ExecuteReader_DbConnectionPlus)] )] - public void ExecuteReader__Cleanup() => - this.connection.Dispose(); + public void ExecuteReader__Cleanup() => this.connection.Dispose(); [GlobalSetup( - Targets = - [ - nameof(ExecuteReader_Command), - nameof(ExecuteReader_Dapper), - nameof(ExecuteReader_DbConnectionPlus) - ] + Targets = [nameof(ExecuteReader_Command), nameof(ExecuteReader_Dapper), nameof(ExecuteReader_DbConnectionPlus)] )] - public void ExecuteReader__Setup() => - this.SetupDatabase(100); + public void ExecuteReader__Setup() => this.SetupDatabase(100); [Benchmark(Baseline = true)] [BenchmarkCategory(ExecuteReader_Category)] diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteScalar.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteScalar.cs index bf8e5bb..a4cde04 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteScalar.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteScalar.cs @@ -8,26 +8,14 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { [GlobalCleanup( - Targets = - [ - nameof(ExecuteScalar_Command), - nameof(ExecuteScalar_Dapper), - nameof(ExecuteScalar_DbConnectionPlus) - ] + Targets = [nameof(ExecuteScalar_Command), nameof(ExecuteScalar_Dapper), nameof(ExecuteScalar_DbConnectionPlus)] )] - public void ExecuteScalar__Cleanup() => - this.connection.Dispose(); + public void ExecuteScalar__Cleanup() => this.connection.Dispose(); [GlobalSetup( - Targets = - [ - nameof(ExecuteScalar_Command), - nameof(ExecuteScalar_Dapper), - nameof(ExecuteScalar_DbConnectionPlus) - ] + Targets = [nameof(ExecuteScalar_Command), nameof(ExecuteScalar_Dapper), nameof(ExecuteScalar_DbConnectionPlus)] )] - public void ExecuteScalar__Setup() => - this.SetupDatabase(1); + public void ExecuteScalar__Setup() => this.SetupDatabase(1); [Benchmark(Baseline = true)] [BenchmarkCategory(ExecuteScalar_Category)] diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Exists.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Exists.cs index 90c850e..cc03580 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Exists.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Exists.cs @@ -7,27 +7,11 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { - [GlobalCleanup( - Targets = - [ - nameof(Exists_Command), - nameof(Exists_Dapper), - nameof(Exists_DbConnectionPlus) - ] - )] - public void Exists__Cleanup() => - this.connection.Dispose(); - - [GlobalSetup( - Targets = - [ - nameof(Exists_Command), - nameof(Exists_Dapper), - nameof(Exists_DbConnectionPlus) - ] - )] - public void Exists__Setup() => - this.SetupDatabase(1); + [GlobalCleanup(Targets = [nameof(Exists_Command), nameof(Exists_Dapper), nameof(Exists_DbConnectionPlus)])] + public void Exists__Cleanup() => this.connection.Dispose(); + + [GlobalSetup(Targets = [nameof(Exists_Command), nameof(Exists_Dapper), nameof(Exists_DbConnectionPlus)])] + public void Exists__Setup() => this.SetupDatabase(1); [Benchmark(Baseline = true)] [BenchmarkCategory(Exists_Category)] diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntities.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntities.cs index b382879..872bf23 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntities.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntities.cs @@ -8,26 +8,22 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { [GlobalCleanup( - Targets = - [ + Targets = [ nameof(InsertEntities_Command), nameof(InsertEntities_Dapper), - nameof(InsertEntities_DbConnectionPlus) + nameof(InsertEntities_DbConnectionPlus), ] )] - public void InsertEntities__Cleanup() => - this.connection.Dispose(); + public void InsertEntities__Cleanup() => this.connection.Dispose(); [GlobalSetup( - Targets = - [ + Targets = [ nameof(InsertEntities_Command), nameof(InsertEntities_Dapper), - nameof(InsertEntities_DbConnectionPlus) + nameof(InsertEntities_DbConnectionPlus), ] )] - public void InsertEntities__Setup() => - this.SetupDatabase(0); + public void InsertEntities__Setup() => this.SetupDatabase(0); [Benchmark(Baseline = true)] [BenchmarkCategory(InsertEntities_Category)] @@ -54,7 +50,7 @@ public void InsertEntities_Command() { "Int32Value", new("Int32Value", null) }, { "Int64Value", new("Int64Value", null) }, { "SingleValue", new("SingleValue", null) }, - { "StringValue", new("StringValue", null) } + { "StringValue", new("StringValue", null) }, }; command.Parameters.AddRange(parameters.Values); @@ -97,8 +93,9 @@ private void AssignNextInsertEntitiesIds() } } - private readonly List insertEntities_entitiesToInsert = - Generate.Multiple(InsertEntities_EntitiesPerOperation); + private readonly List insertEntities_entitiesToInsert = Generate.Multiple( + InsertEntities_EntitiesPerOperation + ); private long insertEntities_nextId; @@ -106,39 +103,39 @@ private void AssignNextInsertEntitiesIds() private const int InsertEntities_EntitiesPerOperation = 200; private const string InsertEntitySql = """ - INSERT INTO Entity - ( - Id, - BooleanValue, - BytesValue, - ByteValue, - CharValue, - DateTimeValue, - DecimalValue, - DoubleValue, - EnumValue, - Int16Value, - Int32Value, - Int64Value, - SingleValue, - StringValue - ) - VALUES - ( - @Id, - @BooleanValue, - @BytesValue, - @ByteValue, - @CharValue, - @DateTimeValue, - @DecimalValue, - @DoubleValue, - @EnumValue, - @Int16Value, - @Int32Value, - @Int64Value, - @SingleValue, - @StringValue - ) - """; + INSERT INTO Entity + ( + Id, + BooleanValue, + BytesValue, + ByteValue, + CharValue, + DateTimeValue, + DecimalValue, + DoubleValue, + EnumValue, + Int16Value, + Int32Value, + Int64Value, + SingleValue, + StringValue + ) + VALUES + ( + @Id, + @BooleanValue, + @BytesValue, + @ByteValue, + @CharValue, + @DateTimeValue, + @DecimalValue, + @DoubleValue, + @EnumValue, + @Int16Value, + @Int32Value, + @Int64Value, + @SingleValue, + @StringValue + ) + """; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntity.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntity.cs index b384e77..3a3fb0a 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntity.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntity.cs @@ -8,26 +8,14 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { [GlobalCleanup( - Targets = - [ - nameof(InsertEntity_Command), - nameof(InsertEntity_Dapper), - nameof(InsertEntity_DbConnectionPlus) - ] + Targets = [nameof(InsertEntity_Command), nameof(InsertEntity_Dapper), nameof(InsertEntity_DbConnectionPlus)] )] - public void InsertEntity__Cleanup() => - this.connection.Dispose(); + public void InsertEntity__Cleanup() => this.connection.Dispose(); [GlobalSetup( - Targets = - [ - nameof(InsertEntity_Command), - nameof(InsertEntity_Dapper), - nameof(InsertEntity_DbConnectionPlus) - ] + Targets = [nameof(InsertEntity_Command), nameof(InsertEntity_Dapper), nameof(InsertEntity_DbConnectionPlus)] )] - public void InsertEntity__Setup() => - this.SetupDatabase(0); + public void InsertEntity__Setup() => this.SetupDatabase(0); [Benchmark(Baseline = true)] [BenchmarkCategory(InsertEntity_Category)] @@ -54,7 +42,7 @@ public void InsertEntity_Command() { "Int32Value", new("Int32Value", null) }, { "Int64Value", new("Int64Value", null) }, { "SingleValue", new("SingleValue", null) }, - { "StringValue", new("StringValue", null) } + { "StringValue", new("StringValue", null) }, }; command.Parameters.AddRange(parameters.Values); @@ -82,8 +70,7 @@ public void InsertEntity_DbConnectionPlus() this.connection.InsertEntity(this.insertEntity_entityToInsert); } - private void AssignNextInsertEntityId() => - this.insertEntity_entityToInsert.Id = ++this.insertEntity_nextId; + private void AssignNextInsertEntityId() => this.insertEntity_entityToInsert.Id = ++this.insertEntity_nextId; private readonly BenchmarkEntity insertEntity_entityToInsert = Generate.Single(); diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Parameter.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Parameter.cs index 6eee0a5..12d8391 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Parameter.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Parameter.cs @@ -7,27 +7,11 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { - [GlobalCleanup( - Targets = - [ - nameof(Parameter_Command), - nameof(Parameter_Dapper), - nameof(Parameter_DbConnectionPlus) - ] - )] - public void Parameter__Cleanup() => - this.connection.Dispose(); + [GlobalCleanup(Targets = [nameof(Parameter_Command), nameof(Parameter_Dapper), nameof(Parameter_DbConnectionPlus)])] + public void Parameter__Cleanup() => this.connection.Dispose(); - [GlobalSetup( - Targets = - [ - nameof(Parameter_Command), - nameof(Parameter_Dapper), - nameof(Parameter_DbConnectionPlus) - ] - )] - public void Parameter__Setup() => - this.SetupDatabase(0); + [GlobalSetup(Targets = [nameof(Parameter_Command), nameof(Parameter_Dapper), nameof(Parameter_DbConnectionPlus)])] + public void Parameter__Setup() => this.SetupDatabase(0); [Benchmark(Baseline = true)] [BenchmarkCategory(Parameter_Category)] @@ -57,7 +41,19 @@ public long Parameter_Dapper() => SqlMapper.ExecuteScalar( this.connection, "SELECT @P1 + @P2 + @P3 + @P4 + @P5 + @P6 + @P7 + @P8 + @P9 + @P10", - new { P1 = 1, P2 = 2, P3 = 3, P4 = 4, P5 = 5, P6 = 6, P7 = 7, P8 = 8, P9 = 9, P10 = 10 } + new + { + P1 = 1, + P2 = 2, + P3 = 3, + P4 = 4, + P5 = 5, + P6 = 6, + P7 = 7, + P8 = 8, + P9 = 9, + P10 = 10, + } ); [Benchmark(Baseline = false)] @@ -65,9 +61,9 @@ public long Parameter_Dapper() => public long Parameter_DbConnectionPlus() => this.connection.ExecuteScalar( $""" - SELECT {Parameter(1)} + {Parameter(2)} + {Parameter(3)} + {Parameter(4)} + {Parameter(5)} + - {Parameter(6)} + {Parameter(7)} + {Parameter(8)} + {Parameter(9)} + {Parameter(10)} - """ + SELECT {Parameter(1)} + {Parameter(2)} + {Parameter(3)} + {Parameter(4)} + {Parameter(5)} + + {Parameter(6)} + {Parameter(7)} + {Parameter(8)} + {Parameter(9)} + {Parameter(10)} + """ ); private const string Parameter_Category = "Parameter"; diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Dynamic.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Dynamic.cs index 32f868f..9e67945 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Dynamic.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Dynamic.cs @@ -10,26 +10,14 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { [GlobalCleanup( - Targets = - [ - nameof(Query_Dynamic_Command), - nameof(Query_Dynamic_Dapper), - nameof(Query_Dynamic_DbConnectionPlus) - ] + Targets = [nameof(Query_Dynamic_Command), nameof(Query_Dynamic_Dapper), nameof(Query_Dynamic_DbConnectionPlus)] )] - public void Query_Dynamic__Cleanup() => - this.connection.Dispose(); + public void Query_Dynamic__Cleanup() => this.connection.Dispose(); [GlobalSetup( - Targets = - [ - nameof(Query_Dynamic_Command), - nameof(Query_Dynamic_Dapper), - nameof(Query_Dynamic_DbConnectionPlus) - ] + Targets = [nameof(Query_Dynamic_Command), nameof(Query_Dynamic_Dapper), nameof(Query_Dynamic_DbConnectionPlus)] )] - public void Query_Dynamic__Setup() => - this.SetupDatabase(Query_Dynamic_EntitiesPerOperation); + public void Query_Dynamic__Setup() => this.SetupDatabase(Query_Dynamic_EntitiesPerOperation); [Benchmark(Baseline = true)] [BenchmarkCategory(Query_Dynamic_Category)] @@ -51,9 +39,10 @@ public List Query_Dynamic_Command() ["BooleanValue"] = dataReader.GetInt64(ordinal++) == 1, ["BytesValue"] = (byte[])dataReader.GetValue(ordinal++), ["ByteValue"] = dataReader.GetByte(ordinal++), - ["CharValue"] = dataReader.GetChars(ordinal++, 0, charBuffer, 0, 1) == 1 - ? charBuffer[0] - : throw new InvalidOperationException(), + ["CharValue"] = + dataReader.GetChars(ordinal++, 0, charBuffer, 0, 1) == 1 + ? charBuffer[0] + : throw new InvalidOperationException(), ["DateTimeValue"] = DateTime.Parse(dataReader.GetString(ordinal++), CultureInfo.InvariantCulture), ["DecimalValue"] = decimal.Parse(dataReader.GetString(ordinal++), CultureInfo.InvariantCulture), ["DoubleValue"] = dataReader.GetDouble(ordinal++), @@ -62,7 +51,7 @@ public List Query_Dynamic_Command() ["Int32Value"] = (int)dataReader.GetInt64(ordinal++), ["Int64Value"] = dataReader.GetInt64(ordinal++), ["SingleValue"] = dataReader.GetFloat(ordinal++), - ["StringValue"] = dataReader.GetString(ordinal) + ["StringValue"] = dataReader.GetString(ordinal), }; entities.Add(new DataRow(dictionary)); @@ -73,13 +62,11 @@ public List Query_Dynamic_Command() [Benchmark(Baseline = false)] [BenchmarkCategory(Query_Dynamic_Category)] - public List Query_Dynamic_Dapper() => - [.. SqlMapper.Query(this.connection, "SELECT * FROM Entity")]; + public List Query_Dynamic_Dapper() => [.. SqlMapper.Query(this.connection, "SELECT * FROM Entity")]; [Benchmark(Baseline = false)] [BenchmarkCategory(Query_Dynamic_Category)] - public List Query_Dynamic_DbConnectionPlus() => - [.. this.connection.Query("SELECT * FROM Entity")]; + public List Query_Dynamic_DbConnectionPlus() => [.. this.connection.Query("SELECT * FROM Entity")]; private const string Query_Dynamic_Category = "Query_Dynamic"; private const int Query_Dynamic_EntitiesPerOperation = 100; diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Entities.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Entities.cs index 9c90324..ccae5cc 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Entities.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Entities.cs @@ -8,28 +8,24 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { [GlobalCleanup( - Targets = - [ + Targets = [ nameof(Query_Entities_Command), nameof(Query_Entities_Dapper), nameof(Query_Entities_Dapper_Aot), - nameof(Query_Entities_DbConnectionPlus) + nameof(Query_Entities_DbConnectionPlus), ] )] - public void Query_Entities__Cleanup() => - this.connection.Dispose(); + public void Query_Entities__Cleanup() => this.connection.Dispose(); [GlobalSetup( - Targets = - [ + Targets = [ nameof(Query_Entities_Command), nameof(Query_Entities_Dapper), nameof(Query_Entities_Dapper_Aot), - nameof(Query_Entities_DbConnectionPlus) + nameof(Query_Entities_DbConnectionPlus), ] )] - public void Query_Entities__Setup() => - this.SetupDatabase(Query_Entities_EntitiesPerOperation); + public void Query_Entities__Setup() => this.SetupDatabase(Query_Entities_EntitiesPerOperation); [Benchmark(Baseline = true)] [BenchmarkCategory(Query_Entities_Category)] diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Scalars.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Scalars.cs index f754fc2..5985eab 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Scalars.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Scalars.cs @@ -8,26 +8,14 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { [GlobalCleanup( - Targets = - [ - nameof(Query_Scalars_Command), - nameof(Query_Scalars_Dapper), - nameof(Query_Scalars_DbConnectionPlus) - ] + Targets = [nameof(Query_Scalars_Command), nameof(Query_Scalars_Dapper), nameof(Query_Scalars_DbConnectionPlus)] )] - public void Query_Scalars__Cleanup() => - this.connection.Dispose(); + public void Query_Scalars__Cleanup() => this.connection.Dispose(); [GlobalSetup( - Targets = - [ - nameof(Query_Scalars_Command), - nameof(Query_Scalars_Dapper), - nameof(Query_Scalars_DbConnectionPlus) - ] + Targets = [nameof(Query_Scalars_Command), nameof(Query_Scalars_Dapper), nameof(Query_Scalars_DbConnectionPlus)] )] - public void Query_Scalars__Setup() => - this.SetupDatabase(Query_Scalars_EntitiesPerOperation); + public void Query_Scalars__Setup() => this.SetupDatabase(Query_Scalars_EntitiesPerOperation); [Benchmark(Baseline = true)] [BenchmarkCategory(Query_Scalars_Category)] @@ -51,13 +39,11 @@ public List Query_Scalars_Command() [Benchmark(Baseline = false)] [BenchmarkCategory(Query_Scalars_Category)] - public List Query_Scalars_Dapper() => - [.. SqlMapper.Query(this.connection, "SELECT Id FROM Entity")]; + public List Query_Scalars_Dapper() => [.. SqlMapper.Query(this.connection, "SELECT Id FROM Entity")]; [Benchmark(Baseline = false)] [BenchmarkCategory(Query_Scalars_Category)] - public List Query_Scalars_DbConnectionPlus() => - [.. this.connection.Query("SELECT Id FROM Entity")]; + public List Query_Scalars_DbConnectionPlus() => [.. this.connection.Query("SELECT Id FROM Entity")]; private const string Query_Scalars_Category = "Query_Scalars"; private const int Query_Scalars_EntitiesPerOperation = 600; diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_ValueTuples.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_ValueTuples.cs index d76598a..fe57da2 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_ValueTuples.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_ValueTuples.cs @@ -8,31 +8,26 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { [GlobalCleanup( - Targets = - [ + Targets = [ nameof(Query_ValueTuples_Command), nameof(Query_ValueTuples_Dapper), - nameof(Query_ValueTuples_DbConnectionPlus) + nameof(Query_ValueTuples_DbConnectionPlus), ] )] - public void Query_ValueTuples__Cleanup() => - this.connection.Dispose(); + public void Query_ValueTuples__Cleanup() => this.connection.Dispose(); [GlobalSetup( - Targets = - [ + Targets = [ nameof(Query_ValueTuples_Command), nameof(Query_ValueTuples_Dapper), - nameof(Query_ValueTuples_DbConnectionPlus) + nameof(Query_ValueTuples_DbConnectionPlus), ] )] - public void Query_ValueTuples__Setup() => - this.SetupDatabase(Query_ValueTuples_EntitiesPerOperation); + public void Query_ValueTuples__Setup() => this.SetupDatabase(Query_ValueTuples_EntitiesPerOperation); [Benchmark(Baseline = true)] [BenchmarkCategory(Query_ValueTuples_Category)] - public List<(long Id, DateTime DateTimeValue, TestEnum EnumValue, string StringValue)> - Query_ValueTuples_Command() + public List<(long Id, DateTime DateTimeValue, TestEnum EnumValue, string StringValue)> Query_ValueTuples_Command() { var result = new List<(long Id, DateTime DateTimeValue, TestEnum EnumValue, string StringValue)>(); @@ -59,13 +54,13 @@ public void Query_ValueTuples__Setup() => [Benchmark(Baseline = false)] [BenchmarkCategory(Query_ValueTuples_Category)] - public List<(long Id, DateTime DateTimeValue, TestEnum EnumValue, string StringValue)> - Query_ValueTuples_Dapper() => - [.. SqlMapper - .Query<(long Id, DateTime DateTimeValue, TestEnum EnumValue, string StringValue)>( + public List<(long Id, DateTime DateTimeValue, TestEnum EnumValue, string StringValue)> Query_ValueTuples_Dapper() => + [ + .. SqlMapper.Query<(long Id, DateTime DateTimeValue, TestEnum EnumValue, string StringValue)>( this.connection, "SELECT Id, DateTimeValue, EnumValue, StringValue FROM Entity" - )]; + ), + ]; // There is no Query_ValueTuples_Dapper_Aot benchmark, so this category's Native AOT group compares // DbConnectionPlus against the raw DbCommand baseline alone. Dapper.AOT's generator does not materialize value @@ -75,12 +70,17 @@ [.. SqlMapper [Benchmark(Baseline = false)] [BenchmarkCategory(Query_ValueTuples_Category)] - public List<(long Id, DateTime DateTimeValue, TestEnum EnumValue, string StringValue)> - Query_ValueTuples_DbConnectionPlus() => - [.. this.connection - .Query<(long Id, DateTime DateTimeValue, TestEnum EnumValue, string StringValue)>( + public List<( + long Id, + DateTime DateTimeValue, + TestEnum EnumValue, + string StringValue + )> Query_ValueTuples_DbConnectionPlus() => + [ + .. this.connection.Query<(long Id, DateTime DateTimeValue, TestEnum EnumValue, string StringValue)>( "SELECT Id, DateTimeValue, EnumValue, StringValue FROM Entity" - )]; + ), + ]; private const string Query_ValueTuples_Category = "Query_ValueTuples"; private const int Query_ValueTuples_EntitiesPerOperation = 150; diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ComplexObjects.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ComplexObjects.cs index 009b103..476cd0b 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ComplexObjects.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ComplexObjects.cs @@ -8,22 +8,19 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { [GlobalCleanup( - Targets = - [ + Targets = [ nameof(TemporaryTable_ComplexObjects_Command), nameof(TemporaryTable_ComplexObjects_Dapper), - nameof(TemporaryTable_ComplexObjects_DbConnectionPlus) + nameof(TemporaryTable_ComplexObjects_DbConnectionPlus), ] )] - public void TemporaryTable_ComplexObjects__Cleanup() => - this.connection.Dispose(); + public void TemporaryTable_ComplexObjects__Cleanup() => this.connection.Dispose(); [GlobalSetup( - Targets = - [ + Targets = [ nameof(TemporaryTable_ComplexObjects_Command), nameof(TemporaryTable_ComplexObjects_Dapper), - nameof(TemporaryTable_ComplexObjects_DbConnectionPlus) + nameof(TemporaryTable_ComplexObjects_DbConnectionPlus), ] )] public void TemporaryTable_ComplexObjects__Setup() => @@ -58,7 +55,7 @@ public List TemporaryTable_ComplexObjects_Command() { "Int32Value", new("Int32Value", null) }, { "Int64Value", new("Int64Value", null) }, { "SingleValue", new("SingleValue", null) }, - { "StringValue", new("StringValue", null) } + { "StringValue", new("StringValue", null) }, }; insertCommand.Parameters.AddRange(parameters.Values); @@ -124,64 +121,69 @@ public List TemporaryTable_ComplexObjects_Dapper() [Benchmark(Baseline = false)] [BenchmarkCategory(TemporaryTable_ComplexObjects_Category)] public List TemporaryTable_ComplexObjects_DbConnectionPlus() => - [.. this.connection.Query($"SELECT * FROM {TemporaryTable(this.temporaryTable_ComplexObjects_Entities)}")]; + [ + .. this.connection.Query( + $"SELECT * FROM {TemporaryTable(this.temporaryTable_ComplexObjects_Entities)}" + ), + ]; - private readonly List temporaryTable_ComplexObjects_Entities = - Generate.Multiple(TemporaryTable_ComplexObjects_EntitiesPerOperation); + private readonly List temporaryTable_ComplexObjects_Entities = Generate.Multiple( + TemporaryTable_ComplexObjects_EntitiesPerOperation + ); private const string CreateTempEntitiesTableSql = """ - CREATE TEMP TABLE Entities ( - Id INTEGER, - BooleanValue INTEGER, - BytesValue BLOB, - ByteValue INTEGER, - CharValue TEXT, - DateTimeValue TEXT, - DecimalValue TEXT, - DoubleValue REAL, - EnumValue TEXT, - Int16Value INTEGER, - Int32Value INTEGER, - Int64Value INTEGER, - SingleValue REAL, - StringValue TEXT - ) - """; + CREATE TEMP TABLE Entities ( + Id INTEGER, + BooleanValue INTEGER, + BytesValue BLOB, + ByteValue INTEGER, + CharValue TEXT, + DateTimeValue TEXT, + DecimalValue TEXT, + DoubleValue REAL, + EnumValue TEXT, + Int16Value INTEGER, + Int32Value INTEGER, + Int64Value INTEGER, + SingleValue REAL, + StringValue TEXT + ) + """; private const string InsertIntoTempEntities = """ - INSERT INTO temp.Entities ( - Id, - BooleanValue, - BytesValue, - ByteValue, - CharValue, - DateTimeValue, - DecimalValue, - DoubleValue, - EnumValue, - Int16Value, - Int32Value, - Int64Value, - SingleValue, - StringValue - ) - VALUES ( - @Id, - @BooleanValue, - @BytesValue, - @ByteValue, - @CharValue, - @DateTimeValue, - @DecimalValue, - @DoubleValue, - @EnumValue, - @Int16Value, - @Int32Value, - @Int64Value, - @SingleValue, - @StringValue - ) - """; + INSERT INTO temp.Entities ( + Id, + BooleanValue, + BytesValue, + ByteValue, + CharValue, + DateTimeValue, + DecimalValue, + DoubleValue, + EnumValue, + Int16Value, + Int32Value, + Int64Value, + SingleValue, + StringValue + ) + VALUES ( + @Id, + @BooleanValue, + @BytesValue, + @ByteValue, + @CharValue, + @DateTimeValue, + @DecimalValue, + @DoubleValue, + @EnumValue, + @Int16Value, + @Int32Value, + @Int64Value, + @SingleValue, + @StringValue + ) + """; private const string TemporaryTable_ComplexObjects_Category = "TemporaryTable_ComplexObjects"; private const int TemporaryTable_ComplexObjects_EntitiesPerOperation = 250; diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ScalarValues.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ScalarValues.cs index 5fd71fc..e141783 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ScalarValues.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ScalarValues.cs @@ -8,26 +8,22 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { [GlobalCleanup( - Targets = - [ + Targets = [ nameof(TemporaryTable_ScalarValues_Command), nameof(TemporaryTable_ScalarValues_Dapper), - nameof(TemporaryTable_ScalarValues_DbConnectionPlus) + nameof(TemporaryTable_ScalarValues_DbConnectionPlus), ] )] - public void TemporaryTable_ScalarValues__Cleanup() => - this.connection.Dispose(); + public void TemporaryTable_ScalarValues__Cleanup() => this.connection.Dispose(); [GlobalSetup( - Targets = - [ + Targets = [ nameof(TemporaryTable_ScalarValues_Command), nameof(TemporaryTable_ScalarValues_Dapper), - nameof(TemporaryTable_ScalarValues_DbConnectionPlus) + nameof(TemporaryTable_ScalarValues_DbConnectionPlus), ] )] - public void TemporaryTable_ScalarValues__Setup() => - this.SetupDatabase(0); + public void TemporaryTable_ScalarValues__Setup() => this.SetupDatabase(0); [Benchmark(Baseline = true)] [BenchmarkCategory(TemporaryTable_ScalarValues_Category)] @@ -40,10 +36,7 @@ public List TemporaryTable_ScalarValues_Command() using var insertCommand = this.connection.CreateCommand(); insertCommand.CommandText = "INSERT INTO temp.\"Values\" (Value) VALUES (@Value)"; - var valueParameter = new SqliteParameter - { - ParameterName = "@Value" - }; + var valueParameter = new SqliteParameter { ParameterName = "@Value" }; insertCommand.Parameters.Add(valueParameter); @@ -97,11 +90,16 @@ public List TemporaryTable_ScalarValues_Dapper() [Benchmark(Baseline = false)] [BenchmarkCategory(TemporaryTable_ScalarValues_Category)] public List TemporaryTable_ScalarValues_DbConnectionPlus() => - [.. this.connection.Query($"SELECT Value FROM {TemporaryTable(this.temporaryTable_ScalarValues_Values)}")]; - - private readonly List temporaryTable_ScalarValues_Values = [.. Enumerable - .Range(0, TemporaryTable_ScalarValues_ValuesPerOperation) - .Select(a => (long)a)]; + [ + .. this.connection.Query( + $"SELECT Value FROM {TemporaryTable(this.temporaryTable_ScalarValues_Values)}" + ), + ]; + + private readonly List temporaryTable_ScalarValues_Values = + [ + .. Enumerable.Range(0, TemporaryTable_ScalarValues_ValuesPerOperation).Select(a => (long)a), + ]; private const string TemporaryTable_ScalarValues_Category = "TemporaryTable_ScalarValues"; private const int TemporaryTable_ScalarValues_ValuesPerOperation = 5000; diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntities.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntities.cs index 4ca05a9..e75bcce 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntities.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntities.cs @@ -8,22 +8,19 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { [GlobalCleanup( - Targets = - [ + Targets = [ nameof(UpdateEntities_Command), nameof(UpdateEntities_Dapper), - nameof(UpdateEntities_DbConnectionPlus) + nameof(UpdateEntities_DbConnectionPlus), ] )] - public void UpdateEntities__Cleanup() => - this.connection.Dispose(); + public void UpdateEntities__Cleanup() => this.connection.Dispose(); [GlobalSetup( - Targets = - [ + Targets = [ nameof(UpdateEntities_Command), nameof(UpdateEntities_Dapper), - nameof(UpdateEntities_DbConnectionPlus) + nameof(UpdateEntities_DbConnectionPlus), ] )] public void UpdateEntities__Setup() @@ -37,13 +34,14 @@ public void UpdateEntities__Setup() [ .. Enumerable .Range(0, UpdateEntities_UpdatedEntitiesPoolSize) - .Select(_ => Generate.UpdatesFor(this.entitiesInDb)) + .Select(_ => Generate.UpdatesFor(this.entitiesInDb)), ]; } private List UpdateEntities_GetNextModifiedEntities() { - this.updateEntities_ModifiedEntitiesPoolIndex = (this.updateEntities_ModifiedEntitiesPoolIndex + 1) % UpdateEntities_UpdatedEntitiesPoolSize; + this.updateEntities_ModifiedEntitiesPoolIndex = + (this.updateEntities_ModifiedEntitiesPoolIndex + 1) % UpdateEntities_UpdatedEntitiesPoolSize; return this.updateEntities_ModifiedEntitiesPool[this.updateEntities_ModifiedEntitiesPoolIndex]; } @@ -57,22 +55,22 @@ public void UpdateEntities_Command() using var command = this.connection.CreateCommand(); command.CommandText = """ - UPDATE Entity - SET BooleanValue = @BooleanValue, - BytesValue = @BytesValue, - ByteValue = @ByteValue, - CharValue = @CharValue, - DateTimeValue = @DateTimeValue, - DecimalValue = @DecimalValue, - DoubleValue = @DoubleValue, - EnumValue = @EnumValue, - Int16Value = @Int16Value, - Int32Value = @Int32Value, - Int64Value = @Int64Value, - SingleValue = @SingleValue, - StringValue = @StringValue - WHERE Id = @Id - """; + UPDATE Entity + SET BooleanValue = @BooleanValue, + BytesValue = @BytesValue, + ByteValue = @ByteValue, + CharValue = @CharValue, + DateTimeValue = @DateTimeValue, + DecimalValue = @DecimalValue, + DoubleValue = @DoubleValue, + EnumValue = @EnumValue, + Int16Value = @Int16Value, + Int32Value = @Int32Value, + Int64Value = @Int64Value, + SingleValue = @SingleValue, + StringValue = @StringValue + WHERE Id = @Id + """; var parameters = new Dictionary { @@ -89,7 +87,7 @@ UPDATE Entity { "Int32Value", new("Int32Value", null) }, { "Int64Value", new("Int64Value", null) }, { "SingleValue", new("SingleValue", null) }, - { "StringValue", new("StringValue", null) } + { "StringValue", new("StringValue", null) }, }; command.Parameters.AddRange(parameters.Values); diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntity.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntity.cs index 67a6162..1e56998 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntity.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntity.cs @@ -8,23 +8,12 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { [GlobalCleanup( - Targets = - [ - nameof(UpdateEntity_Command), - nameof(UpdateEntity_Dapper), - nameof(UpdateEntity_DbConnectionPlus) - ] + Targets = [nameof(UpdateEntity_Command), nameof(UpdateEntity_Dapper), nameof(UpdateEntity_DbConnectionPlus)] )] - public void UpdateEntity__Cleanup() => - this.connection.Dispose(); + public void UpdateEntity__Cleanup() => this.connection.Dispose(); [GlobalSetup( - Targets = - [ - nameof(UpdateEntity_Command), - nameof(UpdateEntity_Dapper), - nameof(UpdateEntity_DbConnectionPlus) - ] + Targets = [nameof(UpdateEntity_Command), nameof(UpdateEntity_Dapper), nameof(UpdateEntity_DbConnectionPlus)] )] public void UpdateEntity__Setup() { @@ -41,13 +30,14 @@ public void UpdateEntity__Setup() [ .. Enumerable .Range(0, UpdateEntity_UpdatedEntityPoolSize) - .Select(_ => Generate.UpdateFor(this.entitiesInDb[0])) + .Select(_ => Generate.UpdateFor(this.entitiesInDb[0])), ]; } private BenchmarkEntity UpdateEntity_GetNextModifiedEntity() { - this.updateEntity_ModifiedEntitiesPoolIndex = (this.updateEntity_ModifiedEntitiesPoolIndex + 1) % UpdateEntity_UpdatedEntityPoolSize; + this.updateEntity_ModifiedEntitiesPoolIndex = + (this.updateEntity_ModifiedEntitiesPoolIndex + 1) % UpdateEntity_UpdatedEntityPoolSize; return this.updateEntity_ModifiedEntitiesPool[this.updateEntity_ModifiedEntitiesPoolIndex]; } @@ -61,22 +51,22 @@ public void UpdateEntity_Command() using var command = this.connection.CreateCommand(); command.CommandText = """ - UPDATE Entity - SET BooleanValue = @BooleanValue, - BytesValue = @BytesValue, - ByteValue = @ByteValue, - CharValue = @CharValue, - DateTimeValue = @DateTimeValue, - DecimalValue = @DecimalValue, - DoubleValue = @DoubleValue, - EnumValue = @EnumValue, - Int16Value = @Int16Value, - Int32Value = @Int32Value, - Int64Value = @Int64Value, - SingleValue = @SingleValue, - StringValue = @StringValue - WHERE Id = @Id - """; + UPDATE Entity + SET BooleanValue = @BooleanValue, + BytesValue = @BytesValue, + ByteValue = @ByteValue, + CharValue = @CharValue, + DateTimeValue = @DateTimeValue, + DecimalValue = @DecimalValue, + DoubleValue = @DoubleValue, + EnumValue = @EnumValue, + Int16Value = @Int16Value, + Int32Value = @Int32Value, + Int64Value = @Int64Value, + SingleValue = @SingleValue, + StringValue = @StringValue + WHERE Id = @Id + """; var parameters = new Dictionary { @@ -93,7 +83,7 @@ UPDATE Entity { "Int32Value", new("Int32Value", null) }, { "Int64Value", new("Int64Value", null) }, { "SingleValue", new("SingleValue", null) }, - { "StringValue", new("StringValue", null) } + { "StringValue", new("StringValue", null) }, }; command.Parameters.AddRange(parameters.Values); diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.cs index 67aec8d..475c95f 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.cs @@ -13,8 +13,7 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; [Config(typeof(BenchmarksConfig))] public partial class Benchmarks { - static Benchmarks() => - DbConnectionPlusConfiguration.Instance.UseSqlite(); + static Benchmarks() => DbConnectionPlusConfiguration.Instance.UseSqlite(); public Benchmarks() { @@ -77,7 +76,10 @@ private static BenchmarkEntity ReadEntity(IDataReader dataReader) BooleanValue = dataReader.GetInt64(ordinal++) == 1, BytesValue = (byte[])dataReader.GetValue(ordinal++), ByteValue = dataReader.GetByte(ordinal++), - CharValue = dataReader.GetChars(ordinal++, 0, charBuffer, 0, 1) == 1 ? charBuffer[0] : throw new InvalidOperationException(), + CharValue = + dataReader.GetChars(ordinal++, 0, charBuffer, 0, 1) == 1 + ? charBuffer[0] + : throw new InvalidOperationException(), DateTimeValue = DateTime.Parse(dataReader.GetString(ordinal++), CultureInfo.InvariantCulture), DecimalValue = decimal.Parse(dataReader.GetString(ordinal++), CultureInfo.InvariantCulture), DoubleValue = dataReader.GetDouble(ordinal++), @@ -86,7 +88,7 @@ private static BenchmarkEntity ReadEntity(IDataReader dataReader) Int32Value = (int)dataReader.GetInt64(ordinal++), Int64Value = dataReader.GetInt64(ordinal++), SingleValue = dataReader.GetFloat(ordinal++), - StringValue = dataReader.GetString(ordinal) + StringValue = dataReader.GetString(ordinal), }; } @@ -99,8 +101,7 @@ private static BenchmarkEntity ReadEntity(IDataReader dataReader) * update, exists and scalar benchmarks and made their results a function of the seeded row count rather than of * the code under test. */ - private const string CreateEntityTableSql = - """ + private const string CreateEntityTableSql = """ CREATE TABLE Entity ( Id INTEGER PRIMARY KEY, diff --git a/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksConfig.cs b/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksConfig.cs index c001ad2..fd6570a 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksConfig.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksConfig.cs @@ -38,8 +38,8 @@ public BenchmarksConfig() // The settings both jobs share, so that the only difference between them is the toolchain. private static Job CreateJob(string id) => - Job.Default - .WithId(id) + Job + .Default.WithId(id) // The default adaptive warmup runs ~9 iterations, but every iteration already executes tens of // thousands of invocations, so the tiered JIT has reached steady state before the first warmup // iteration completes. Three is enough; the rest was pure wall time. diff --git a/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksOrderer.cs b/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksOrderer.cs index 8421e59..4fef65f 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksOrderer.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksOrderer.cs @@ -22,16 +22,11 @@ public class BenchmarksOrderer : IOrderer public IEnumerable GetExecutionOrder( ImmutableArray benchmarksCase, IEnumerable? order = null - ) => - Sort(benchmarksCase); + ) => Sort(benchmarksCase); - public string? GetHighlightGroupKey(BenchmarkCase benchmarkCase) => - GetLogicalGroupKey(benchmarkCase); + public string? GetHighlightGroupKey(BenchmarkCase benchmarkCase) => GetLogicalGroupKey(benchmarkCase); - public string? GetLogicalGroupKey( - ImmutableArray allBenchmarksCases, - BenchmarkCase benchmarkCase - ) => + public string? GetLogicalGroupKey(ImmutableArray allBenchmarksCases, BenchmarkCase benchmarkCase) => GetLogicalGroupKey(benchmarkCase); public IEnumerable> GetLogicalGroupOrder( @@ -42,10 +37,7 @@ public IEnumerable> GetLogicalGroupOrder( .OrderBy(it => it.First().Descriptor.Categories[0], StringComparer.Ordinal) .ThenBy(it => GetJobRank(it.First())); - public IEnumerable GetSummaryOrder( - ImmutableArray benchmarksCases, - Summary summary - ) => + public IEnumerable GetSummaryOrder(ImmutableArray benchmarksCases, Summary summary) => Sort(benchmarksCases); private static IEnumerable Sort(ImmutableArray benchmarkCases) => diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Program.cs b/benchmarks/DbConnectionPlus.Benchmarks/Program.cs index 2591a77..50d2822 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Program.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Program.cs @@ -4,8 +4,5 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public static class Program { - public static void Main(string[] args) => - BenchmarkSwitcher - .FromAssembly(typeof(Program).Assembly) - .Run(args); + public static void Main(string[] args) => BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/TestData/Generate.cs b/benchmarks/DbConnectionPlus.Benchmarks/TestData/Generate.cs index 1439afb..9dd8ee2 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/TestData/Generate.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/TestData/Generate.cs @@ -22,8 +22,7 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks.TestData; // three for Double and Single, and alphabetic characters only for Char. public static class Generate { - public static BenchmarkEntity Single() => - Create(NextId()); + public static BenchmarkEntity Single() => Create(NextId()); public static List Multiple(int numberOfEntities) => [.. Enumerable.Range(0, numberOfEntities).Select(_ => Single())]; @@ -42,8 +41,7 @@ public static BenchmarkEntity UpdateFor(BenchmarkEntity entity) return updatedEntity; } - public static List UpdatesFor(List entities) => - [.. entities.Select(UpdateFor)]; + public static List UpdatesFor(List entities) => [.. entities.Select(UpdateFor)]; private static BenchmarkEntity Create(long id) { @@ -66,13 +64,12 @@ private static BenchmarkEntity Create(long id) Int32Value = random.Next(int.MinValue, int.MaxValue), Int64Value = random.NextInt64(), SingleValue = (float)Math.Round(random.NextDouble() * 999.0, 3), - StringValue = NextSentence() + StringValue = NextSentence(), }; } } - private static long NextId() => - Interlocked.Increment(ref nextId); + private static long NextId() => Interlocked.Increment(ref nextId); private static byte[] NextBytes(int count) { @@ -93,10 +90,7 @@ private static string NextSentence() sentence[i] = words[random.Next(0, words.Length)]; } - sentence[0] = string.Concat( - sentence[0][..1].ToUpper(CultureInfo.InvariantCulture), - sentence[0].AsSpan(1) - ); + sentence[0] = string.Concat(sentence[0][..1].ToUpper(CultureInfo.InvariantCulture), sentence[0].AsSpan(1)); return string.Join(' ', sentence) + '.'; } @@ -114,9 +108,39 @@ private static string NextSentence() private static readonly string[] words = [ - "lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing", "elit", "sed", "do", "eiusmod", - "tempor", "incididunt", "ut", "labore", "et", "dolore", "magna", "aliqua", "enim", "ad", "minim", "veniam", - "quis", "nostrud", "exercitation", "ullamco", "laboris", "nisi", "aliquip", "ex", "ea", "commodo" + "lorem", + "ipsum", + "dolor", + "sit", + "amet", + "consectetur", + "adipiscing", + "elit", + "sed", + "do", + "eiusmod", + "tempor", + "incididunt", + "ut", + "labore", + "et", + "dolore", + "magna", + "aliqua", + "enim", + "ad", + "minim", + "veniam", + "quis", + "nostrud", + "exercitation", + "ullamco", + "laboris", + "nisi", + "aliquip", + "ex", + "ea", + "commodo", ]; private static readonly DateTime dateTimeBase = new(2020, 1, 1, 0, 0, 0, DateTimeKind.Local); diff --git a/benchmarks/DbConnectionPlus.Benchmarks/TestData/TestEnum.cs b/benchmarks/DbConnectionPlus.Benchmarks/TestData/TestEnum.cs index 1677b51..619ac04 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/TestData/TestEnum.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/TestData/TestEnum.cs @@ -6,5 +6,5 @@ public enum TestEnum Value2 = 2, Value3 = 3, Value4 = 4, - Value5 = 5 + Value5 = 5, } diff --git a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlConfigurationExtensions.cs b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlConfigurationExtensions.cs index 87d64c7..4873dad 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlConfigurationExtensions.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlConfigurationExtensions.cs @@ -3,6 +3,7 @@ #pragma warning disable IDE0130 namespace RentADeveloper.DbConnectionPlus.Configuration; + #pragma warning restore IDE0130 /// diff --git a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlDatabaseAdapter.cs b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlDatabaseAdapter.cs index 2d2ffb1..9eaee12 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlDatabaseAdapter.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlDatabaseAdapter.cs @@ -23,8 +23,7 @@ public MySqlDatabaseAdapter() public IEntityManipulator EntityManipulator => this.entityManipulator; /// - public ITemporaryTableBuilder TemporaryTableBuilder => - this.temporaryTableBuilder; + public ITemporaryTableBuilder TemporaryTableBuilder => this.temporaryTableBuilder; /// public void BindParameterValue(DbParameter parameter, object? value) @@ -41,16 +40,13 @@ public void BindParameterValue(DbParameter parameter, object? value) case Enum enumValue: parameter.DbType = DbConnectionPlusConfiguration.Instance.EnumSerializationMode switch { - EnumSerializationMode.Integers => - DbType.Int32, + EnumSerializationMode.Integers => DbType.Int32, - EnumSerializationMode.Strings => - DbType.String, + EnumSerializationMode.Strings => DbType.String, - _ => - ThrowHelper.ThrowInvalidEnumSerializationModeException( - DbConnectionPlusConfiguration.Instance.EnumSerializationMode - ) + _ => ThrowHelper.ThrowInvalidEnumSerializationModeException( + DbConnectionPlusConfiguration.Instance.EnumSerializationMode + ), }; parameter.Value = EnumSerializer.SerializeEnum( @@ -71,8 +67,7 @@ public void BindParameterValue(DbParameter parameter, object? value) } /// - public string FormatParameterName(string parameterName) => - "@" + parameterName; + public string FormatParameterName(string parameterName) => "@" + parameterName; /// public string GetDataType(Type type, EnumSerializationMode enumSerializationMode) @@ -86,13 +81,11 @@ public string GetDataType(Type type, EnumSerializationMode enumSerializationMode { return enumSerializationMode switch { - EnumSerializationMode.Strings => - "VARCHAR(200)", // 200 should be enough for most enum names + EnumSerializationMode.Strings => "VARCHAR(200)", // 200 should be enough for most enum names - EnumSerializationMode.Integers => - "INT", + EnumSerializationMode.Integers => "INT", - _ => ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode) + _ => ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode), }; } @@ -109,16 +102,13 @@ public string GetDataType(Type type, EnumSerializationMode enumSerializationMode } /// - public string QuoteIdentifier(string identifier) => - "`" + identifier + "`"; + public string QuoteIdentifier(string identifier) => "`" + identifier + "`"; /// - public string QuoteTemporaryTableName(string tableName, DbConnection connection) => - "`" + tableName + "`"; + public string QuoteTemporaryTableName(string tableName, DbConnection connection) => "`" + tableName + "`"; /// - public bool SupportsTemporaryTables(DbConnection connection) => - true; + public bool SupportsTemporaryTables(DbConnection connection) => true; /// public bool WasSqlStatementCancelledByCancellationToken(Exception exception, CancellationToken cancellationToken) @@ -149,6 +139,6 @@ public bool WasSqlStatementCancelledByCancellationToken(Exception exception, Can { typeof(float), "FLOAT" }, { typeof(string), "TEXT" }, { typeof(TimeOnly), "TIME" }, - { typeof(TimeSpan), "TIME" } + { typeof(TimeSpan), "TIME" }, }; } diff --git a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlEntityManipulator.cs index bc1d03c..244d650 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlEntityManipulator.cs @@ -18,14 +18,11 @@ internal class MySqlEntityManipulator : IEntityManipulator /// /// The database adapter to use to manipulate entities. #pragma warning disable IDE0290 // Use primary constructor - public MySqlEntityManipulator(MySqlDatabaseAdapter databaseAdapter) => - this.databaseAdapter = databaseAdapter; + public MySqlEntityManipulator(MySqlDatabaseAdapter databaseAdapter) => this.databaseAdapter = databaseAdapter; #pragma warning restore IDE0290 // Use primary constructor /// - public int DeleteEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int DeleteEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -72,11 +69,8 @@ CancellationToken cancellationToken totalNumberOfAffectedRows += numberOfAffectedRows; } } - catch (Exception exception) when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -86,9 +80,7 @@ CancellationToken cancellationToken } /// - public async Task DeleteEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task DeleteEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -121,8 +113,9 @@ CancellationToken cancellationToken DbConnectionExtensions.OnBeforeExecutingCommand(command, []); - var numberOfAffectedRows = - await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false); + var numberOfAffectedRows = await command + .ExecuteNonQueryAsync(cancellationToken) + .ConfigureAwait(false); if (numberOfAffectedRows != 1) { @@ -136,11 +129,8 @@ CancellationToken cancellationToken totalNumberOfAffectedRows += numberOfAffectedRows; } } - catch (Exception exception) when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -150,9 +140,7 @@ CancellationToken cancellationToken } /// - public int DeleteEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int DeleteEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -189,11 +177,8 @@ CancellationToken cancellationToken return numberOfAffectedRows; } - catch (Exception exception) when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -201,9 +186,7 @@ CancellationToken cancellationToken } /// - public async Task DeleteEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task DeleteEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -240,11 +223,8 @@ CancellationToken cancellationToken return numberOfAffectedRows; } - catch (Exception exception) when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -252,9 +232,7 @@ CancellationToken cancellationToken } /// - public int InsertEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int InsertEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -266,11 +244,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateInsertEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateInsertEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -297,9 +271,8 @@ CancellationToken cancellationToken totalNumberOfAffectedRows += reader.RecordsAffected; } } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -309,9 +282,7 @@ CancellationToken cancellationToken } /// - public async Task InsertEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task InsertEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -323,11 +294,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateInsertEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateInsertEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -350,22 +317,18 @@ CancellationToken cancellationToken #pragma warning disable CA2007 await using var reader = await command - .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken).ConfigureAwait(false); + .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken) + .ConfigureAwait(false); #pragma warning restore CA2007 - await UpdateDatabaseGeneratedPropertiesAsync( - entityTypeMetadata, - reader, - entity, - cancellationToken - ).ConfigureAwait(false); + await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, cancellationToken) + .ConfigureAwait(false); totalNumberOfAffectedRows += reader.RecordsAffected; } } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -375,9 +338,7 @@ await UpdateDatabaseGeneratedPropertiesAsync( } /// - public int InsertEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int InsertEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -389,11 +350,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateInsertEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateInsertEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -411,9 +368,8 @@ CancellationToken cancellationToken return reader.RecordsAffected; } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -421,9 +377,7 @@ CancellationToken cancellationToken } /// - public async Task InsertEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task InsertEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -435,11 +389,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateInsertEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateInsertEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -453,7 +403,8 @@ CancellationToken cancellationToken #pragma warning disable CA2007 await using var reader = await command - .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken).ConfigureAwait(false); + .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken) + .ConfigureAwait(false); #pragma warning restore CA2007 await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, cancellationToken) @@ -461,9 +412,8 @@ await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, return reader.RecordsAffected; } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -471,9 +421,7 @@ await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, } /// - public int UpdateEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int UpdateEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -485,11 +433,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateUpdateEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateUpdateEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -531,9 +475,8 @@ CancellationToken cancellationToken totalNumberOfAffectedRows += reader.RecordsAffected; } } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -543,9 +486,7 @@ CancellationToken cancellationToken } /// - public async Task UpdateEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task UpdateEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -557,11 +498,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateUpdateEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateUpdateEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -584,15 +521,12 @@ CancellationToken cancellationToken #pragma warning disable CA2007 await using var reader = await command - .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken).ConfigureAwait(false); + .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken) + .ConfigureAwait(false); #pragma warning restore CA2007 - await UpdateDatabaseGeneratedPropertiesAsync( - entityTypeMetadata, - reader, - entity, - cancellationToken - ).ConfigureAwait(false); + await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, cancellationToken) + .ConfigureAwait(false); // We must close the reader before we can access DbDataReader.RecordsAffected, because otherwise it // returns -1 when we select database generated properties via the SELECT statement after the @@ -611,9 +545,8 @@ await UpdateDatabaseGeneratedPropertiesAsync( totalNumberOfAffectedRows += reader.RecordsAffected; } } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -623,9 +556,7 @@ await UpdateDatabaseGeneratedPropertiesAsync( } /// - public int UpdateEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int UpdateEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -637,11 +568,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateUpdateEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateUpdateEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -673,9 +600,8 @@ CancellationToken cancellationToken return reader.RecordsAffected; } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -683,9 +609,7 @@ CancellationToken cancellationToken } /// - public async Task UpdateEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task UpdateEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -697,11 +621,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateUpdateEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateUpdateEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -738,9 +658,8 @@ await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, return reader.RecordsAffected; } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -772,8 +691,8 @@ EntityTypeMetadata entityTypeMetadata var parameters = new List(); - var whereProperties = entityTypeMetadata.KeyProperties - .Concat(entityTypeMetadata.ConcurrencyTokenProperties) + var whereProperties = entityTypeMetadata + .KeyProperties.Concat(entityTypeMetadata.ConcurrencyTokenProperties) .Concat(entityTypeMetadata.RowVersionProperties); foreach (var property in whereProperties) @@ -888,8 +807,8 @@ private string GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => var prependSeparator = false; - var whereProperties = entityTypeMetadata.KeyProperties - .Concat(entityTypeMetadata.ConcurrencyTokenProperties) + var whereProperties = entityTypeMetadata + .KeyProperties.Concat(entityTypeMetadata.ConcurrencyTokenProperties) .Concat(entityTypeMetadata.RowVersionProperties); foreach (var keyProperty in whereProperties) @@ -1097,8 +1016,8 @@ private string GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => prependSeparator = false; - var whereProperties = entityTypeMetadata.KeyProperties - .Concat(entityTypeMetadata.ConcurrencyTokenProperties) + var whereProperties = entityTypeMetadata + .KeyProperties.Concat(entityTypeMetadata.ConcurrencyTokenProperties) .Concat(entityTypeMetadata.RowVersionProperties); foreach (var property in whereProperties) @@ -1159,7 +1078,7 @@ private string GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => whereProperties = [ .. entityTypeMetadata.KeyProperties, - .. entityTypeMetadata.ConcurrencyTokenProperties + .. entityTypeMetadata.ConcurrencyTokenProperties, ]; foreach (var keyProperty in whereProperties) @@ -1261,8 +1180,8 @@ CancellationToken cancellationToken ) { if ( - entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 && - await reader.ReadAsync(cancellationToken).ConfigureAwait(false) + entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 + && await reader.ReadAsync(cancellationToken).ConfigureAwait(false) ) { for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) diff --git a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlTemporaryTableBuilder.cs b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlTemporaryTableBuilder.cs index f7070e3..0c2a0d9 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlTemporaryTableBuilder.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlTemporaryTableBuilder.cs @@ -36,8 +36,7 @@ public TemporaryTableDisposer BuildTemporaryTable( DbTransaction? transaction, string name, IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, CancellationToken cancellationToken = default ) { @@ -69,8 +68,10 @@ public TemporaryTableDisposer BuildTemporaryTable( ); createCommand.Transaction = transaction; - using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken); + using var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation( + createCommand, + cancellationToken + ); DbConnectionExtensions.OnBeforeExecutingCommand(createCommand, []); @@ -87,8 +88,10 @@ public TemporaryTableDisposer BuildTemporaryTable( ); createCommand.Transaction = transaction; - using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken); + using var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation( + createCommand, + cancellationToken + ); DbConnectionExtensions.OnBeforeExecutingCommand(createCommand, []); @@ -100,7 +103,7 @@ public TemporaryTableDisposer BuildTemporaryTable( var mySqlBulkCopy = new MySqlBulkCopy(mySqlConnection, mySqlTransaction) { BulkCopyTimeout = 0, - DestinationTableName = $"`{name}`" + DestinationTableName = $"`{name}`", }; mySqlBulkCopy.ColumnMappings.Clear(); @@ -111,7 +114,9 @@ public TemporaryTableDisposer BuildTemporaryTable( } else { - var properties = EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a.CanRead) + var properties = EntityHelper + .GetEntityTypeMetadata(valuesType) + .MappedProperties.Where(a => a.CanRead) .ToList(); for (var i = 0; i < properties.Count; i++) @@ -136,8 +141,7 @@ public async Task BuildTemporaryTableAsync( DbTransaction? transaction, string name, IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, CancellationToken cancellationToken = default ) { @@ -173,7 +177,7 @@ public async Task BuildTemporaryTableAsync( await using var cancellationTokenRegistration = #pragma warning disable CA2007 - DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken); + DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken); #pragma warning restore CA2007 DbConnectionExtensions.OnBeforeExecutingCommand(createCommand, []); @@ -194,9 +198,9 @@ public async Task BuildTemporaryTableAsync( createCommand.Transaction = transaction; - await using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken) - .ConfigureAwait(false); + await using var cancellationTokenRegistration = DbCommandHelper + .RegisterDbCommandCancellation(createCommand, cancellationToken) + .ConfigureAwait(false); DbConnectionExtensions.OnBeforeExecutingCommand(createCommand, []); @@ -210,7 +214,7 @@ public async Task BuildTemporaryTableAsync( var mySqlBulkCopy = new MySqlBulkCopy(mySqlConnection, mySqlTransaction) { BulkCopyTimeout = 0, - DestinationTableName = $"`{name}`" + DestinationTableName = $"`{name}`", }; mySqlBulkCopy.ColumnMappings.Clear(); @@ -221,7 +225,9 @@ public async Task BuildTemporaryTableAsync( } else { - var properties = EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a.CanRead) + var properties = EntityHelper + .GetEntityTypeMetadata(valuesType) + .MappedProperties.Where(a => a.CanRead) .ToList(); for (var i = 0; i < properties.Count; i++) @@ -240,7 +246,6 @@ public async Task BuildTemporaryTableAsync( ); } - /// /// Builds an SQL code to create a multi-column temporary table to be populated with objects of the type /// . @@ -251,8 +256,7 @@ public async Task BuildTemporaryTableAsync( /// The built SQL code. private string BuildCreateMultiColumnTemporaryTableSqlCode( string tableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type objectsType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type objectsType, EnumSerializationMode enumSerializationMode ) { @@ -302,8 +306,7 @@ EnumSerializationMode enumSerializationMode /// The built SQL code. private string BuildCreateSingleColumnTemporaryTableSqlCode( string tableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, EnumSerializationMode enumSerializationMode ) { @@ -333,8 +336,8 @@ EnumSerializationMode enumSerializationMode /// private static EnumerableReader CreateValuesDataReader( IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType) + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType + ) { if (valuesType.IsBuiltInTypeOrNullableBuiltInType() || valuesType.IsEnumOrNullableEnumType()) { diff --git a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleConfigurationExtensions.cs b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleConfigurationExtensions.cs index 3d9767e..fbfc0c4 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleConfigurationExtensions.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleConfigurationExtensions.cs @@ -3,6 +3,7 @@ #pragma warning disable IDE0130 namespace RentADeveloper.DbConnectionPlus.Configuration; + #pragma warning restore IDE0130 /// diff --git a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleDatabaseAdapter.cs b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleDatabaseAdapter.cs index 0e0783e..df208e6 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleDatabaseAdapter.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleDatabaseAdapter.cs @@ -57,16 +57,13 @@ public void BindParameterValue(DbParameter parameter, object? value) case Enum enumValue: parameter.DbType = DbConnectionPlusConfiguration.Instance.EnumSerializationMode switch { - EnumSerializationMode.Integers => - DbType.Int32, + EnumSerializationMode.Integers => DbType.Int32, - EnumSerializationMode.Strings => - DbType.String, + EnumSerializationMode.Strings => DbType.String, - _ => - ThrowHelper.ThrowInvalidEnumSerializationModeException( - DbConnectionPlusConfiguration.Instance.EnumSerializationMode - ) + _ => ThrowHelper.ThrowInvalidEnumSerializationModeException( + DbConnectionPlusConfiguration.Instance.EnumSerializationMode + ), }; parameter.Value = EnumSerializer.SerializeEnum( @@ -98,8 +95,7 @@ public void BindParameterValue(DbParameter parameter, object? value) } /// - public string FormatParameterName(string parameterName) => - ":\"" + parameterName + "\""; + public string FormatParameterName(string parameterName) => ":\"" + parameterName + "\""; /// public string GetDataType(Type type, EnumSerializationMode enumSerializationMode) @@ -113,14 +109,11 @@ public string GetDataType(Type type, EnumSerializationMode enumSerializationMode { return enumSerializationMode switch { - EnumSerializationMode.Strings => - "NVARCHAR2(200)", // 200 should be enough for most enum names + EnumSerializationMode.Strings => "NVARCHAR2(200)", // 200 should be enough for most enum names - EnumSerializationMode.Integers => - "NUMBER(10)", + EnumSerializationMode.Integers => "NUMBER(10)", - _ => - ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode) + _ => ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode), }; } @@ -174,14 +167,11 @@ public DbType GetDbType(Type type, EnumSerializationMode enumSerializationMode) { return enumSerializationMode switch { - EnumSerializationMode.Strings => - DbType.String, + EnumSerializationMode.Strings => DbType.String, - EnumSerializationMode.Integers => - DbType.Int32, + EnumSerializationMode.Integers => DbType.Int32, - _ => - ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode) + _ => ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode), }; } @@ -198,8 +188,7 @@ public DbType GetDbType(Type type, EnumSerializationMode enumSerializationMode) } /// - public string QuoteIdentifier(string identifier) => - "\"" + identifier + "\""; + public string QuoteIdentifier(string identifier) => "\"" + identifier + "\""; /// public string QuoteTemporaryTableName(string tableName, DbConnection connection) @@ -224,10 +213,7 @@ public bool SupportsTemporaryTables(DbConnection connection) } /// - public bool WasSqlStatementCancelledByCancellationToken( - Exception exception, - CancellationToken cancellationToken - ) + public bool WasSqlStatementCancelledByCancellationToken(Exception exception, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(exception); @@ -287,10 +273,10 @@ CancellationToken cancellationToken /// Always thrown. internal static void ThrowTemporaryTablesFeatureIsDisabledException() => throw new InvalidOperationException( - "The temporary tables feature of DbConnectionPlus is currently disabled for Oracle databases. " + - $"To enable it set {typeof(OracleDatabaseAdapter)}.{nameof(AllowTemporaryTables)} " + - "to true, but be sure to read the documentation first, because enabling this feature has implications " + - "for transaction management." + "The temporary tables feature of DbConnectionPlus is currently disabled for Oracle databases. " + + $"To enable it set {typeof(OracleDatabaseAdapter)}.{nameof(AllowTemporaryTables)} " + + "to true, but be sure to read the documentation first, because enabling this feature has implications " + + "for transaction management." ); private readonly OracleEntityManipulator entityManipulator; @@ -315,7 +301,7 @@ internal static void ThrowTemporaryTablesFeatureIsDisabledException() => { typeof(float), DbType.Single }, { typeof(string), DbType.String }, { typeof(TimeOnly), DbType.Time }, - { typeof(TimeSpan), DbType.Time } + { typeof(TimeSpan), DbType.Time }, }; private static readonly Dictionary typeToOracleDataType = new() @@ -336,6 +322,6 @@ internal static void ThrowTemporaryTablesFeatureIsDisabledException() => { typeof(float), "BINARY_FLOAT" }, { typeof(string), "NVARCHAR2(2000)" }, { typeof(TimeOnly), "INTERVAL DAY TO SECOND" }, - { typeof(TimeSpan), "INTERVAL DAY TO SECOND" } + { typeof(TimeSpan), "INTERVAL DAY TO SECOND" }, }; } diff --git a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleEntityManipulator.cs index 6bcefce..761814f 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleEntityManipulator.cs @@ -15,9 +15,7 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.Oracle; internal class OracleEntityManipulator(OracleDatabaseAdapter databaseAdapter) : IEntityManipulator { /// - public int DeleteEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int DeleteEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -64,11 +62,8 @@ CancellationToken cancellationToken totalNumberOfAffectedRows += numberOfAffectedRows; } } - catch (Exception exception) when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -78,9 +73,7 @@ CancellationToken cancellationToken } /// - public async Task DeleteEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task DeleteEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -113,8 +106,9 @@ CancellationToken cancellationToken DbConnectionExtensions.OnBeforeExecutingCommand(command, []); - var numberOfAffectedRows = - await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false); + var numberOfAffectedRows = await command + .ExecuteNonQueryAsync(cancellationToken) + .ConfigureAwait(false); if (numberOfAffectedRows != 1) { @@ -128,11 +122,8 @@ CancellationToken cancellationToken totalNumberOfAffectedRows += numberOfAffectedRows; } } - catch (Exception exception) when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -142,9 +133,7 @@ CancellationToken cancellationToken } /// - public int DeleteEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int DeleteEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -181,11 +170,8 @@ CancellationToken cancellationToken return numberOfAffectedRows; } - catch (Exception exception) when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -193,9 +179,7 @@ CancellationToken cancellationToken } /// - public async Task DeleteEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task DeleteEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -232,11 +216,8 @@ CancellationToken cancellationToken return numberOfAffectedRows; } - catch (Exception exception) when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -244,9 +225,7 @@ CancellationToken cancellationToken } /// - public int InsertEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int InsertEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -258,11 +237,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateInsertEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateInsertEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -290,9 +265,8 @@ CancellationToken cancellationToken UpdateDatabaseGeneratedProperties(entityTypeMetadata, outputParameters, entity); } } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -302,9 +276,7 @@ CancellationToken cancellationToken } /// - public async Task InsertEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task InsertEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -316,11 +288,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateInsertEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateInsertEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -341,17 +309,17 @@ CancellationToken cancellationToken DbConnectionExtensions.OnBeforeExecutingCommand(command, []); - totalNumberOfAffectedRows += - await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false); + totalNumberOfAffectedRows += await command + .ExecuteNonQueryAsync(cancellationToken) + .ConfigureAwait(false); var outputParameters = parameters.Where(a => a.Direction == ParameterDirection.Output).ToArray(); UpdateDatabaseGeneratedProperties(entityTypeMetadata, outputParameters, entity); } } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -361,9 +329,7 @@ CancellationToken cancellationToken } /// - public int InsertEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int InsertEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -375,11 +341,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateInsertEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateInsertEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -399,9 +361,8 @@ CancellationToken cancellationToken return numberOfAffectedRows; } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -409,9 +370,7 @@ CancellationToken cancellationToken } /// - public async Task InsertEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task InsertEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -423,11 +382,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateInsertEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateInsertEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -447,9 +402,8 @@ CancellationToken cancellationToken return numberOfAffectedRows; } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -457,9 +411,7 @@ CancellationToken cancellationToken } /// - public int UpdateEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int UpdateEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -471,11 +423,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateUpdateEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateUpdateEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -514,9 +462,8 @@ CancellationToken cancellationToken UpdateDatabaseGeneratedProperties(entityTypeMetadata, outputParameters, entity); } } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -526,9 +473,7 @@ CancellationToken cancellationToken } /// - public async Task UpdateEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task UpdateEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -540,11 +485,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateUpdateEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateUpdateEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -565,8 +506,9 @@ CancellationToken cancellationToken DbConnectionExtensions.OnBeforeExecutingCommand(command, []); - var numberOfAffectedRows = - await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false); + var numberOfAffectedRows = await command + .ExecuteNonQueryAsync(cancellationToken) + .ConfigureAwait(false); if (numberOfAffectedRows != 1) { @@ -584,9 +526,8 @@ CancellationToken cancellationToken UpdateDatabaseGeneratedProperties(entityTypeMetadata, outputParameters, entity); } } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -596,9 +537,7 @@ CancellationToken cancellationToken } /// - public int UpdateEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int UpdateEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -610,11 +549,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateUpdateEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateUpdateEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -643,9 +578,8 @@ CancellationToken cancellationToken return numberOfAffectedRows; } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -653,9 +587,7 @@ CancellationToken cancellationToken } /// - public async Task UpdateEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task UpdateEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -667,11 +599,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateUpdateEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateUpdateEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -700,9 +628,8 @@ CancellationToken cancellationToken return numberOfAffectedRows; } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -734,8 +661,8 @@ EntityTypeMetadata entityTypeMetadata var parameters = new List(); - var whereProperties = entityTypeMetadata.KeyProperties - .Concat(entityTypeMetadata.ConcurrencyTokenProperties) + var whereProperties = entityTypeMetadata + .KeyProperties.Concat(entityTypeMetadata.ConcurrencyTokenProperties) .Concat(entityTypeMetadata.RowVersionProperties); foreach (var property in whereProperties) @@ -833,8 +760,8 @@ EntityTypeMetadata entityTypeMetadata var parameters = new List(); - var whereProperties = entityTypeMetadata.KeyProperties - .Concat(entityTypeMetadata.ConcurrencyTokenProperties) + var whereProperties = entityTypeMetadata + .KeyProperties.Concat(entityTypeMetadata.ConcurrencyTokenProperties) .Concat(entityTypeMetadata.RowVersionProperties); foreach (var property in entityTypeMetadata.UpdateProperties.Concat(whereProperties)) @@ -901,8 +828,8 @@ private string GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => var prependSeparator = false; - var whereProperties = entityTypeMetadata.KeyProperties - .Concat(entityTypeMetadata.ConcurrencyTokenProperties) + var whereProperties = entityTypeMetadata + .KeyProperties.Concat(entityTypeMetadata.ConcurrencyTokenProperties) .Concat(entityTypeMetadata.RowVersionProperties); foreach (var keyProperty in whereProperties) @@ -1085,8 +1012,8 @@ private string GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => prependSeparator = false; - var whereProperties = entityTypeMetadata.KeyProperties - .Concat(entityTypeMetadata.ConcurrencyTokenProperties) + var whereProperties = entityTypeMetadata + .KeyProperties.Concat(entityTypeMetadata.ConcurrencyTokenProperties) .Concat(entityTypeMetadata.RowVersionProperties); foreach (var property in whereProperties) diff --git a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleTemporaryTableBuilder.cs b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleTemporaryTableBuilder.cs index 980b82a..49c03a1 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleTemporaryTableBuilder.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleTemporaryTableBuilder.cs @@ -38,8 +38,7 @@ public TemporaryTableDisposer BuildTemporaryTable( DbTransaction? transaction, string name, IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, CancellationToken cancellationToken = default ) { @@ -80,8 +79,10 @@ public TemporaryTableDisposer BuildTemporaryTable( ); createCommand.Transaction = transaction; - using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken); + using var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation( + createCommand, + cancellationToken + ); DbConnectionExtensions.OnBeforeExecutingCommand(createCommand, []); @@ -98,8 +99,10 @@ public TemporaryTableDisposer BuildTemporaryTable( ); createCommand.Transaction = transaction; - using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken); + using var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation( + createCommand, + cancellationToken + ); DbConnectionExtensions.OnBeforeExecutingCommand(createCommand, []); @@ -133,8 +136,7 @@ public async Task BuildTemporaryTableAsync( DbTransaction? transaction, string name, IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, CancellationToken cancellationToken = default ) { @@ -177,8 +179,9 @@ public async Task BuildTemporaryTableAsync( ); createCommand.Transaction = transaction; - await using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken).ConfigureAwait(false); + await using var cancellationTokenRegistration = DbCommandHelper + .RegisterDbCommandCancellation(createCommand, cancellationToken) + .ConfigureAwait(false); DbConnectionExtensions.OnBeforeExecutingCommand(createCommand, []); @@ -197,8 +200,9 @@ public async Task BuildTemporaryTableAsync( ); createCommand.Transaction = transaction; - await using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken).ConfigureAwait(false); + await using var cancellationTokenRegistration = DbCommandHelper + .RegisterDbCommandCancellation(createCommand, cancellationToken) + .ConfigureAwait(false); DbConnectionExtensions.OnBeforeExecutingCommand(createCommand, []); @@ -236,8 +240,7 @@ await this.PopulateTemporaryTableAsync( /// The built SQL code. private string BuildCreateMultiColumnTemporaryTableSqlCode( string quotedTableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type objectsType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type objectsType, EnumSerializationMode enumSerializationMode ) { @@ -288,8 +291,7 @@ EnumSerializationMode enumSerializationMode private string BuildCreateSingleColumnTemporaryTableSqlCode( string quotedTableName, IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, EnumSerializationMode enumSerializationMode ) { @@ -355,8 +357,7 @@ private void PopulateTemporaryTable( OracleConnection connection, OracleTransaction? transaction, string quotedTableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, DbDataReader dataReader, CancellationToken cancellationToken ) @@ -404,8 +405,7 @@ private async Task PopulateTemporaryTableAsync( OracleConnection connection, OracleTransaction? transaction, string quotedTableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, DbDataReader dataReader, CancellationToken cancellationToken ) @@ -449,8 +449,7 @@ CancellationToken cancellationToken /// A tuple containing the insert SQL code and the parameters to use. private static (string SqlCode, OracleParameter[] Parameters) BuildInsertSqlCode( string quotedTableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, DbDataReader dataReader ) { @@ -471,14 +470,13 @@ DbDataReader dataReader sqlBuilder.Append(Constants.SingleColumnTemporaryTableColumnName); sqlBuilder.Append("\""); - parameters[0] = new() - { - ParameterName = Constants.SingleColumnTemporaryTableColumnName - }; + parameters[0] = new() { ParameterName = Constants.SingleColumnTemporaryTableColumnName }; } else { - var properties = EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a.CanRead) + var properties = EntityHelper + .GetEntityTypeMetadata(valuesType) + .MappedProperties.Where(a => a.CanRead) .ToList(); for (var i = 0; i < properties.Count; i++) @@ -494,10 +492,7 @@ DbDataReader dataReader sqlBuilder.Append(property.ColumnName); sqlBuilder.Append('"'); - parameters[i] = new() - { - ParameterName = property.PropertyName - }; + parameters[i] = new() { ParameterName = property.PropertyName }; } } @@ -531,8 +526,8 @@ DbDataReader dataReader /// A that provides access to the data in . private static EnumerableReader CreateValuesDataReader( IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType) + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType + ) { if (valuesType.IsBuiltInTypeOrNullableBuiltInType() || valuesType.IsEnumOrNullableEnumType()) { @@ -546,7 +541,6 @@ [.. EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a ); } - /// /// Drops the temporary table with the specified name. /// diff --git a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlConfigurationExtensions.cs b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlConfigurationExtensions.cs index a2d3507..f14be42 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlConfigurationExtensions.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlConfigurationExtensions.cs @@ -3,6 +3,7 @@ #pragma warning disable IDE0130 namespace RentADeveloper.DbConnectionPlus.Configuration; + #pragma warning restore IDE0130 /// diff --git a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlDatabaseAdapter.cs b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlDatabaseAdapter.cs index a8c3e44..817a105 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlDatabaseAdapter.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlDatabaseAdapter.cs @@ -24,8 +24,7 @@ public PostgreSqlDatabaseAdapter() public IEntityManipulator EntityManipulator => this.entityManipulator; /// - public ITemporaryTableBuilder TemporaryTableBuilder => - this.temporaryTableBuilder; + public ITemporaryTableBuilder TemporaryTableBuilder => this.temporaryTableBuilder; /// public void BindParameterValue(DbParameter parameter, object? value) @@ -42,16 +41,13 @@ public void BindParameterValue(DbParameter parameter, object? value) case Enum enumValue: parameter.DbType = DbConnectionPlusConfiguration.Instance.EnumSerializationMode switch { - EnumSerializationMode.Integers => - DbType.Int32, + EnumSerializationMode.Integers => DbType.Int32, - EnumSerializationMode.Strings => - DbType.String, + EnumSerializationMode.Strings => DbType.String, - _ => - ThrowHelper.ThrowInvalidEnumSerializationModeException( - DbConnectionPlusConfiguration.Instance.EnumSerializationMode - ) + _ => ThrowHelper.ThrowInvalidEnumSerializationModeException( + DbConnectionPlusConfiguration.Instance.EnumSerializationMode + ), }; parameter.Value = EnumSerializer.SerializeEnum( @@ -72,8 +68,7 @@ public void BindParameterValue(DbParameter parameter, object? value) } /// - public string FormatParameterName(string parameterName) => - "@" + parameterName; + public string FormatParameterName(string parameterName) => "@" + parameterName; /// public string GetDataType(Type type, EnumSerializationMode enumSerializationMode) @@ -87,14 +82,11 @@ public string GetDataType(Type type, EnumSerializationMode enumSerializationMode { return enumSerializationMode switch { - EnumSerializationMode.Strings => - "character varying(200)", // 200 should be enough for most enum names + EnumSerializationMode.Strings => "character varying(200)", // 200 should be enough for most enum names - EnumSerializationMode.Integers => - "integer", + EnumSerializationMode.Integers => "integer", - _ => - ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode) + _ => ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode), }; } @@ -150,14 +142,11 @@ public NpgsqlDbType GetDbType(Type type, EnumSerializationMode enumSerialization { return enumSerializationMode switch { - EnumSerializationMode.Strings => - NpgsqlDbType.Varchar, + EnumSerializationMode.Strings => NpgsqlDbType.Varchar, - EnumSerializationMode.Integers => - NpgsqlDbType.Integer, + EnumSerializationMode.Integers => NpgsqlDbType.Integer, - _ => - ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode) + _ => ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode), }; } @@ -174,22 +163,16 @@ public NpgsqlDbType GetDbType(Type type, EnumSerializationMode enumSerialization } /// - public string QuoteIdentifier(string identifier) => - "\"" + identifier + "\""; + public string QuoteIdentifier(string identifier) => "\"" + identifier + "\""; /// - public string QuoteTemporaryTableName(string tableName, DbConnection connection) => - "\"" + tableName + "\""; + public string QuoteTemporaryTableName(string tableName, DbConnection connection) => "\"" + tableName + "\""; /// - public bool SupportsTemporaryTables(DbConnection connection) => - true; + public bool SupportsTemporaryTables(DbConnection connection) => true; /// - public bool WasSqlStatementCancelledByCancellationToken( - Exception exception, - CancellationToken cancellationToken - ) + public bool WasSqlStatementCancelledByCancellationToken(Exception exception, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(exception); @@ -216,7 +199,7 @@ CancellationToken cancellationToken { typeof(float), NpgsqlDbType.Real }, { typeof(string), NpgsqlDbType.Text }, { typeof(TimeOnly), NpgsqlDbType.Time }, - { typeof(TimeSpan), NpgsqlDbType.Interval } + { typeof(TimeSpan), NpgsqlDbType.Interval }, }; private static readonly Dictionary typeToPostgreSqlDataType = new() @@ -236,6 +219,6 @@ CancellationToken cancellationToken { typeof(float), "real" }, { typeof(string), "text" }, { typeof(TimeOnly), "time" }, - { typeof(TimeSpan), "interval" } + { typeof(TimeSpan), "interval" }, }; } diff --git a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlEntityManipulator.cs index ecc21df..c8d68d7 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlEntityManipulator.cs @@ -15,9 +15,7 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.PostgreSql; internal class PostgreSqlEntityManipulator(PostgreSqlDatabaseAdapter databaseAdapter) : IEntityManipulator { /// - public int DeleteEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int DeleteEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -64,11 +62,8 @@ CancellationToken cancellationToken totalNumberOfAffectedRows += numberOfAffectedRows; } } - catch (Exception exception) when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -78,9 +73,7 @@ CancellationToken cancellationToken } /// - public async Task DeleteEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task DeleteEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -113,8 +106,9 @@ CancellationToken cancellationToken DbConnectionExtensions.OnBeforeExecutingCommand(command, []); - var numberOfAffectedRows = - await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false); + var numberOfAffectedRows = await command + .ExecuteNonQueryAsync(cancellationToken) + .ConfigureAwait(false); if (numberOfAffectedRows != 1) { @@ -128,11 +122,8 @@ CancellationToken cancellationToken totalNumberOfAffectedRows += numberOfAffectedRows; } } - catch (Exception exception) when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -142,9 +133,7 @@ CancellationToken cancellationToken } /// - public int DeleteEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int DeleteEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -181,11 +170,8 @@ CancellationToken cancellationToken return numberOfAffectedRows; } - catch (Exception exception) when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -193,9 +179,7 @@ CancellationToken cancellationToken } /// - public async Task DeleteEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task DeleteEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -232,11 +216,8 @@ CancellationToken cancellationToken return numberOfAffectedRows; } - catch (Exception exception) when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -244,9 +225,7 @@ CancellationToken cancellationToken } /// - public int InsertEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int InsertEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -258,11 +237,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateInsertEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateInsertEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -290,9 +265,8 @@ CancellationToken cancellationToken totalNumberOfAffectedRows += reader.RecordsAffected; } } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -302,9 +276,7 @@ CancellationToken cancellationToken } /// - public async Task InsertEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task InsertEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -316,11 +288,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateInsertEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateInsertEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -343,22 +311,18 @@ CancellationToken cancellationToken #pragma warning disable CA2007 await using var reader = await command - .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken).ConfigureAwait(false); + .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken) + .ConfigureAwait(false); #pragma warning restore CA2007 - await UpdateDatabaseGeneratedPropertiesAsync( - entityTypeMetadata, - reader, - entity, - cancellationToken - ).ConfigureAwait(false); + await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, cancellationToken) + .ConfigureAwait(false); totalNumberOfAffectedRows += reader.RecordsAffected; } } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -368,9 +332,7 @@ await UpdateDatabaseGeneratedPropertiesAsync( } /// - public int InsertEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int InsertEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -382,11 +344,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateInsertEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateInsertEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -404,9 +362,8 @@ CancellationToken cancellationToken return reader.RecordsAffected; } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -414,9 +371,7 @@ CancellationToken cancellationToken } /// - public async Task InsertEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task InsertEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -428,11 +383,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateInsertEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateInsertEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -446,7 +397,8 @@ CancellationToken cancellationToken #pragma warning disable CA2007 await using var reader = await command - .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken).ConfigureAwait(false); + .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken) + .ConfigureAwait(false); #pragma warning restore CA2007 await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, cancellationToken) @@ -454,9 +406,8 @@ await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, return reader.RecordsAffected; } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -464,9 +415,7 @@ await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, } /// - public int UpdateEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int UpdateEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -478,11 +427,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateUpdateEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateUpdateEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -523,9 +468,8 @@ CancellationToken cancellationToken totalNumberOfAffectedRows += reader.RecordsAffected; } } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -535,9 +479,7 @@ CancellationToken cancellationToken } /// - public async Task UpdateEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task UpdateEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -549,11 +491,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateUpdateEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateUpdateEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -576,15 +514,12 @@ CancellationToken cancellationToken #pragma warning disable CA2007 await using var reader = await command - .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken).ConfigureAwait(false); + .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken) + .ConfigureAwait(false); #pragma warning restore CA2007 - await UpdateDatabaseGeneratedPropertiesAsync( - entityTypeMetadata, - reader, - entity, - cancellationToken - ).ConfigureAwait(false); + await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, cancellationToken) + .ConfigureAwait(false); // We must close the reader before we can access DbDataReader.RecordsAffected, because otherwise it // returns -1 when we select database generated properties via the RETURNING clause. @@ -602,9 +537,8 @@ await UpdateDatabaseGeneratedPropertiesAsync( totalNumberOfAffectedRows += reader.RecordsAffected; } } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -614,9 +548,7 @@ await UpdateDatabaseGeneratedPropertiesAsync( } /// - public int UpdateEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int UpdateEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -628,11 +560,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateUpdateEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateUpdateEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -663,9 +591,8 @@ CancellationToken cancellationToken return reader.RecordsAffected; } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -673,9 +600,7 @@ CancellationToken cancellationToken } /// - public async Task UpdateEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task UpdateEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -687,11 +612,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateUpdateEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateUpdateEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -727,9 +648,8 @@ await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, return reader.RecordsAffected; } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -761,8 +681,8 @@ EntityTypeMetadata entityTypeMetadata var parameters = new List(); - var whereProperties = entityTypeMetadata.KeyProperties - .Concat(entityTypeMetadata.ConcurrencyTokenProperties) + var whereProperties = entityTypeMetadata + .KeyProperties.Concat(entityTypeMetadata.ConcurrencyTokenProperties) .Concat(entityTypeMetadata.RowVersionProperties); foreach (var property in whereProperties) @@ -878,8 +798,8 @@ private string GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => var prependSeparator = false; - var whereProperties = entityTypeMetadata.KeyProperties - .Concat(entityTypeMetadata.ConcurrencyTokenProperties) + var whereProperties = entityTypeMetadata + .KeyProperties.Concat(entityTypeMetadata.ConcurrencyTokenProperties) .Concat(entityTypeMetadata.RowVersionProperties); foreach (var keyProperty in whereProperties) @@ -1043,8 +963,8 @@ private string GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => prependSeparator = false; - var whereProperties = entityTypeMetadata.KeyProperties - .Concat(entityTypeMetadata.ConcurrencyTokenProperties) + var whereProperties = entityTypeMetadata + .KeyProperties.Concat(entityTypeMetadata.ConcurrencyTokenProperties) .Concat(entityTypeMetadata.RowVersionProperties); foreach (var property in whereProperties) @@ -1169,8 +1089,8 @@ CancellationToken cancellationToken ) { if ( - entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 && - await reader.ReadAsync(cancellationToken).ConfigureAwait(false) + entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 + && await reader.ReadAsync(cancellationToken).ConfigureAwait(false) ) { for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) diff --git a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlTemporaryTableBuilder.cs b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlTemporaryTableBuilder.cs index 21f11a2..2c22d30 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlTemporaryTableBuilder.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlTemporaryTableBuilder.cs @@ -37,8 +37,7 @@ public TemporaryTableDisposer BuildTemporaryTable( DbTransaction? transaction, string name, IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, CancellationToken cancellationToken = default ) { @@ -70,8 +69,10 @@ public TemporaryTableDisposer BuildTemporaryTable( ); createCommand.Transaction = transaction; - using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken); + using var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation( + createCommand, + cancellationToken + ); DbConnectionExtensions.OnBeforeExecutingCommand(createCommand, []); @@ -88,8 +89,10 @@ public TemporaryTableDisposer BuildTemporaryTable( ); createCommand.Transaction = transaction; - using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken); + using var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation( + createCommand, + cancellationToken + ); DbConnectionExtensions.OnBeforeExecutingCommand(createCommand, []); @@ -112,8 +115,7 @@ public async Task BuildTemporaryTableAsync( DbTransaction? transaction, string name, IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, CancellationToken cancellationToken = default ) { @@ -147,8 +149,9 @@ public async Task BuildTemporaryTableAsync( ); createCommand.Transaction = transaction; - await using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken).ConfigureAwait(false); + await using var cancellationTokenRegistration = DbCommandHelper + .RegisterDbCommandCancellation(createCommand, cancellationToken) + .ConfigureAwait(false); DbConnectionExtensions.OnBeforeExecutingCommand(createCommand, []); @@ -167,8 +170,9 @@ public async Task BuildTemporaryTableAsync( ); createCommand.Transaction = transaction; - await using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken).ConfigureAwait(false); + await using var cancellationTokenRegistration = DbCommandHelper + .RegisterDbCommandCancellation(createCommand, cancellationToken) + .ConfigureAwait(false); DbConnectionExtensions.OnBeforeExecutingCommand(createCommand, []); @@ -198,8 +202,7 @@ await this.PopulateTemporaryTableAsync(npgsqlConnection, name, valuesType, reade /// The built SQL code. private string BuildCreateMultiColumnTemporaryTableSqlCode( string tableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type objectsType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type objectsType, EnumSerializationMode enumSerializationMode ) { @@ -249,8 +252,7 @@ EnumSerializationMode enumSerializationMode /// The built SQL code. private string BuildCreateSingleColumnTemporaryTableSqlCode( string tableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, EnumSerializationMode enumSerializationMode ) { @@ -285,8 +287,8 @@ EnumSerializationMode enumSerializationMode /// , so reading the property types here is warning-free and yields the same values. /// private NpgsqlDbType[] GetColumnDbTypes( - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType) + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType + ) { var enumSerializationMode = DbConnectionPlusConfiguration.Instance.EnumSerializationMode; @@ -297,8 +299,10 @@ private NpgsqlDbType[] GetColumnDbTypes( return [ - .. EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a.CanRead) - .Select(a => this.databaseAdapter.GetDbType(a.PropertyType, enumSerializationMode)) + .. EntityHelper + .GetEntityTypeMetadata(valuesType) + .MappedProperties.Where(a => a.CanRead) + .Select(a => this.databaseAdapter.GetDbType(a.PropertyType, enumSerializationMode)), ]; } @@ -313,8 +317,7 @@ .. EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a. private void PopulateTemporaryTable( NpgsqlConnection connection, string tableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, DbDataReader dataReader, CancellationToken cancellationToken ) @@ -368,8 +371,7 @@ CancellationToken cancellationToken private async Task PopulateTemporaryTableAsync( NpgsqlConnection connection, string tableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, DbDataReader dataReader, CancellationToken cancellationToken ) @@ -425,8 +427,8 @@ CancellationToken cancellationToken /// private static EnumerableReader CreateValuesDataReader( IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType) + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType + ) { if (valuesType.IsBuiltInTypeOrNullableBuiltInType() || valuesType.IsEnumOrNullableEnumType()) { diff --git a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerConfigurationExtensions.cs b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerConfigurationExtensions.cs index 0b388f0..58a3411 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerConfigurationExtensions.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerConfigurationExtensions.cs @@ -2,6 +2,7 @@ #pragma warning disable IDE0130 namespace RentADeveloper.DbConnectionPlus.Configuration; + #pragma warning restore IDE0130 /// diff --git a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerDatabaseAdapter.cs b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerDatabaseAdapter.cs index 6609d92..611fff7 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerDatabaseAdapter.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerDatabaseAdapter.cs @@ -23,8 +23,7 @@ public SqlServerDatabaseAdapter() public IEntityManipulator EntityManipulator => this.entityManipulator; /// - public ITemporaryTableBuilder TemporaryTableBuilder => - this.temporaryTableBuilder; + public ITemporaryTableBuilder TemporaryTableBuilder => this.temporaryTableBuilder; /// public void BindParameterValue(DbParameter parameter, object? value) @@ -41,16 +40,13 @@ public void BindParameterValue(DbParameter parameter, object? value) case Enum enumValue: parameter.DbType = DbConnectionPlusConfiguration.Instance.EnumSerializationMode switch { - EnumSerializationMode.Integers => - DbType.Int32, + EnumSerializationMode.Integers => DbType.Int32, - EnumSerializationMode.Strings => - DbType.String, + EnumSerializationMode.Strings => DbType.String, - _ => - ThrowHelper.ThrowInvalidEnumSerializationModeException( - DbConnectionPlusConfiguration.Instance.EnumSerializationMode - ) + _ => ThrowHelper.ThrowInvalidEnumSerializationModeException( + DbConnectionPlusConfiguration.Instance.EnumSerializationMode + ), }; parameter.Value = EnumSerializer.SerializeEnum( @@ -71,8 +67,7 @@ public void BindParameterValue(DbParameter parameter, object? value) } /// - public string FormatParameterName(string parameterName) => - "@" + parameterName; + public string FormatParameterName(string parameterName) => "@" + parameterName; /// public string GetDataType(Type type, EnumSerializationMode enumSerializationMode) @@ -86,14 +81,11 @@ public string GetDataType(Type type, EnumSerializationMode enumSerializationMode { return enumSerializationMode switch { - EnumSerializationMode.Strings => - "nvarchar(200)", // 200 should be enough for most enum names + EnumSerializationMode.Strings => "nvarchar(200)", // 200 should be enough for most enum names - EnumSerializationMode.Integers => - "int", + EnumSerializationMode.Integers => "int", - _ => - ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode) + _ => ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode), }; } @@ -110,22 +102,16 @@ public string GetDataType(Type type, EnumSerializationMode enumSerializationMode } /// - public string QuoteIdentifier(string identifier) => - "[" + identifier + "]"; + public string QuoteIdentifier(string identifier) => "[" + identifier + "]"; /// - public string QuoteTemporaryTableName(string tableName, DbConnection connection) => - "[#" + tableName + "]"; + public string QuoteTemporaryTableName(string tableName, DbConnection connection) => "[#" + tableName + "]"; /// - public bool SupportsTemporaryTables(DbConnection connection) => - true; + public bool SupportsTemporaryTables(DbConnection connection) => true; /// - public bool WasSqlStatementCancelledByCancellationToken( - Exception exception, - CancellationToken cancellationToken - ) + public bool WasSqlStatementCancelledByCancellationToken(Exception exception, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(exception); @@ -177,6 +163,6 @@ CancellationToken cancellationToken { typeof(float), "real" }, { typeof(string), "nvarchar(max)" }, { typeof(TimeOnly), "time" }, - { typeof(TimeSpan), "time" } + { typeof(TimeSpan), "time" }, }; } diff --git a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerEntityManipulator.cs index ef9252b..e558f6e 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerEntityManipulator.cs @@ -15,9 +15,7 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.SqlServer; internal class SqlServerEntityManipulator(SqlServerDatabaseAdapter databaseAdapter) : IEntityManipulator { /// - public int DeleteEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int DeleteEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -64,11 +62,8 @@ CancellationToken cancellationToken totalNumberOfAffectedRows += numberOfAffectedRows; } } - catch (Exception exception) when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -78,9 +73,7 @@ CancellationToken cancellationToken } /// - public async Task DeleteEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task DeleteEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -113,8 +106,9 @@ CancellationToken cancellationToken DbConnectionExtensions.OnBeforeExecutingCommand(command, []); - var numberOfAffectedRows = - await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false); + var numberOfAffectedRows = await command + .ExecuteNonQueryAsync(cancellationToken) + .ConfigureAwait(false); if (numberOfAffectedRows != 1) { @@ -128,11 +122,8 @@ CancellationToken cancellationToken totalNumberOfAffectedRows += numberOfAffectedRows; } } - catch (Exception exception) when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -142,9 +133,7 @@ CancellationToken cancellationToken } /// - public int DeleteEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int DeleteEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -181,11 +170,8 @@ CancellationToken cancellationToken return numberOfAffectedRows; } - catch (Exception exception) when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -193,9 +179,7 @@ CancellationToken cancellationToken } /// - public async Task DeleteEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task DeleteEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -232,11 +216,8 @@ CancellationToken cancellationToken return numberOfAffectedRows; } - catch (Exception exception) when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -244,9 +225,7 @@ CancellationToken cancellationToken } /// - public int InsertEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int InsertEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -258,11 +237,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateInsertEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateInsertEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -290,9 +265,8 @@ CancellationToken cancellationToken totalNumberOfAffectedRows += reader.RecordsAffected; } } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -302,9 +276,7 @@ CancellationToken cancellationToken } /// - public async Task InsertEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task InsertEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -316,11 +288,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateInsertEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateInsertEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -343,22 +311,18 @@ CancellationToken cancellationToken #pragma warning disable CA2007 await using var reader = await command - .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken).ConfigureAwait(false); + .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken) + .ConfigureAwait(false); #pragma warning restore CA2007 - await UpdateDatabaseGeneratedPropertiesAsync( - entityTypeMetadata, - reader, - entity, - cancellationToken - ).ConfigureAwait(false); + await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, cancellationToken) + .ConfigureAwait(false); totalNumberOfAffectedRows += reader.RecordsAffected; } } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -368,9 +332,7 @@ await UpdateDatabaseGeneratedPropertiesAsync( } /// - public int InsertEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int InsertEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -382,11 +344,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateInsertEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateInsertEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -404,9 +362,8 @@ CancellationToken cancellationToken return reader.RecordsAffected; } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -414,9 +371,7 @@ CancellationToken cancellationToken } /// - public async Task InsertEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task InsertEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -428,11 +383,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateInsertEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateInsertEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -446,7 +397,8 @@ CancellationToken cancellationToken #pragma warning disable CA2007 await using var reader = await command - .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken).ConfigureAwait(false); + .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken) + .ConfigureAwait(false); #pragma warning restore CA2007 await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, cancellationToken) @@ -454,9 +406,8 @@ await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, return reader.RecordsAffected; } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -464,9 +415,7 @@ await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, } /// - public int UpdateEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int UpdateEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -478,11 +427,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateUpdateEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateUpdateEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -523,9 +468,8 @@ CancellationToken cancellationToken totalNumberOfAffectedRows += reader.RecordsAffected; } } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -535,9 +479,7 @@ CancellationToken cancellationToken } /// - public async Task UpdateEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task UpdateEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -549,11 +491,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateUpdateEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateUpdateEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -576,15 +514,12 @@ CancellationToken cancellationToken #pragma warning disable CA2007 await using var reader = await command - .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken).ConfigureAwait(false); + .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken) + .ConfigureAwait(false); #pragma warning restore CA2007 - await UpdateDatabaseGeneratedPropertiesAsync( - entityTypeMetadata, - reader, - entity, - cancellationToken - ).ConfigureAwait(false); + await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, cancellationToken) + .ConfigureAwait(false); // We must close the reader before we can access DbDataReader.RecordsAffected, because otherwise it // returns -1 when we select database generated properties via the OUTPUT clause. @@ -602,9 +537,8 @@ await UpdateDatabaseGeneratedPropertiesAsync( totalNumberOfAffectedRows += reader.RecordsAffected; } } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -614,9 +548,7 @@ await UpdateDatabaseGeneratedPropertiesAsync( } /// - public int UpdateEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int UpdateEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -628,11 +560,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateUpdateEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateUpdateEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -663,9 +591,8 @@ CancellationToken cancellationToken return reader.RecordsAffected; } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -673,9 +600,7 @@ CancellationToken cancellationToken } /// - public async Task UpdateEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task UpdateEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -687,11 +612,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateUpdateEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateUpdateEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -727,9 +648,8 @@ await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, return reader.RecordsAffected; } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -761,8 +681,8 @@ EntityTypeMetadata entityTypeMetadata var parameters = new List(); - var whereProperties = entityTypeMetadata.KeyProperties - .Concat(entityTypeMetadata.ConcurrencyTokenProperties) + var whereProperties = entityTypeMetadata + .KeyProperties.Concat(entityTypeMetadata.ConcurrencyTokenProperties) .Concat(entityTypeMetadata.RowVersionProperties); foreach (var property in whereProperties) @@ -878,8 +798,8 @@ private string GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => var prependSeparator = false; - var whereProperties = entityTypeMetadata.KeyProperties - .Concat(entityTypeMetadata.ConcurrencyTokenProperties) + var whereProperties = entityTypeMetadata + .KeyProperties.Concat(entityTypeMetadata.ConcurrencyTokenProperties) .Concat(entityTypeMetadata.RowVersionProperties); foreach (var property in whereProperties) @@ -1067,8 +987,8 @@ private string GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => prependSeparator = false; - var whereProperties = entityTypeMetadata.KeyProperties - .Concat(entityTypeMetadata.ConcurrencyTokenProperties) + var whereProperties = entityTypeMetadata + .KeyProperties.Concat(entityTypeMetadata.ConcurrencyTokenProperties) .Concat(entityTypeMetadata.RowVersionProperties); foreach (var property in whereProperties) @@ -1169,8 +1089,8 @@ CancellationToken cancellationToken ) { if ( - entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 && - await reader.ReadAsync(cancellationToken).ConfigureAwait(false) + entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 + && await reader.ReadAsync(cancellationToken).ConfigureAwait(false) ) { for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) diff --git a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerTemporaryTableBuilder.cs b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerTemporaryTableBuilder.cs index 0b8bfd3..1ef68f1 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerTemporaryTableBuilder.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerTemporaryTableBuilder.cs @@ -35,8 +35,7 @@ public TemporaryTableDisposer BuildTemporaryTable( DbTransaction? transaction, string name, IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, CancellationToken cancellationToken = default ) { @@ -76,8 +75,10 @@ public TemporaryTableDisposer BuildTemporaryTable( ); createCommand.Transaction = transaction; - using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken); + using var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation( + createCommand, + cancellationToken + ); DbConnectionExtensions.OnBeforeExecutingCommand(createCommand, []); @@ -95,8 +96,10 @@ public TemporaryTableDisposer BuildTemporaryTable( ); createCommand.Transaction = transaction; - using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken); + using var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation( + createCommand, + cancellationToken + ); DbConnectionExtensions.OnBeforeExecutingCommand(createCommand, []); @@ -145,8 +148,7 @@ public async Task BuildTemporaryTableAsync( DbTransaction? transaction, string name, IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, CancellationToken cancellationToken = default ) { @@ -188,8 +190,9 @@ public async Task BuildTemporaryTableAsync( createCommand.Transaction = transaction; #pragma warning restore CA2007 - await using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken).ConfigureAwait(false); + await using var cancellationTokenRegistration = DbCommandHelper + .RegisterDbCommandCancellation(createCommand, cancellationToken) + .ConfigureAwait(false); DbConnectionExtensions.OnBeforeExecutingCommand(createCommand, []); @@ -209,8 +212,9 @@ public async Task BuildTemporaryTableAsync( ); createCommand.Transaction = transaction; - await using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken).ConfigureAwait(false); + await using var cancellationTokenRegistration = DbCommandHelper + .RegisterDbCommandCancellation(createCommand, cancellationToken) + .ConfigureAwait(false); DbConnectionExtensions.OnBeforeExecutingCommand(createCommand, []); @@ -262,7 +266,6 @@ public async Task BuildTemporaryTableAsync( ); } - /// /// Builds an SQL code to create a multi-column temporary table to be populated with objects of the type /// . @@ -274,8 +277,7 @@ public async Task BuildTemporaryTableAsync( /// The built SQL code. private string BuildCreateMultiColumnTemporaryTableSqlCode( string tableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type objectsType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type objectsType, string collation, EnumSerializationMode enumSerializationMode ) @@ -310,11 +312,7 @@ EnumSerializationMode enumSerializationMode if ( propertyType == typeof(string) - || - ( - propertyType.IsEnumOrNullableEnumType() && - enumSerializationMode == EnumSerializationMode.Strings - ) + || (propertyType.IsEnumOrNullableEnumType() && enumSerializationMode == EnumSerializationMode.Strings) ) { sqlBuilder.Append(" COLLATE "); @@ -342,8 +340,7 @@ EnumSerializationMode enumSerializationMode private string BuildCreateSingleColumnTemporaryTableSqlCode( string tableName, IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, string collation, EnumSerializationMode enumSerializationMode ) @@ -395,11 +392,7 @@ EnumSerializationMode enumSerializationMode if ( valuesType == typeof(string) - || - ( - valuesType.IsEnumOrNullableEnumType() && - enumSerializationMode == EnumSerializationMode.Strings - ) + || (valuesType.IsEnumOrNullableEnumType() && enumSerializationMode == EnumSerializationMode.Strings) ) { sqlBuilder.Append(" COLLATE "); @@ -419,8 +412,8 @@ EnumSerializationMode enumSerializationMode /// A that provides access to the data in . private static EnumerableReader CreateValuesDataReader( IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType) + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType + ) { if (valuesType.IsBuiltInTypeOrNullableBuiltInType() || valuesType.IsEnumOrNullableEnumType()) { @@ -483,10 +476,7 @@ private static async ValueTask DropTemporaryTableAsync( /// The connection to the database of which to get the collation. /// The database transaction within to perform the operation. /// The collation of the database the specified connection is currently connected to. - private static string GetCurrentDatabaseCollation( - SqlConnection connection, - SqlTransaction? transaction = null - ) => + private static string GetCurrentDatabaseCollation(SqlConnection connection, SqlTransaction? transaction = null) => databaseCollationPerDatabase.GetOrAdd( (connection.DataSource, connection.Database), static (_, args) => @@ -542,6 +532,8 @@ private static async ValueTask GetCurrentDatabaseCollationAsync( private const string GetCurrentDatabaseCollationQuery = "SELECT CONVERT (VARCHAR(256), DATABASEPROPERTYEX(DB_NAME(), 'collation'))"; - private static readonly ConcurrentDictionary<(string DataSource, string Database), string> - databaseCollationPerDatabase = []; + private static readonly ConcurrentDictionary< + (string DataSource, string Database), + string + > databaseCollationPerDatabase = []; } diff --git a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteConfigurationExtensions.cs b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteConfigurationExtensions.cs index 562d8cc..50c090a 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteConfigurationExtensions.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteConfigurationExtensions.cs @@ -3,6 +3,7 @@ #pragma warning disable IDE0130 namespace RentADeveloper.DbConnectionPlus.Configuration; + #pragma warning restore IDE0130 /// diff --git a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteDatabaseAdapter.cs b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteDatabaseAdapter.cs index efa7d59..40eab80 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteDatabaseAdapter.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteDatabaseAdapter.cs @@ -23,8 +23,7 @@ public SqliteDatabaseAdapter() public IEntityManipulator EntityManipulator => this.entityManipulator; /// - public ITemporaryTableBuilder TemporaryTableBuilder => - this.temporaryTableBuilder; + public ITemporaryTableBuilder TemporaryTableBuilder => this.temporaryTableBuilder; /// public void BindParameterValue(DbParameter parameter, object? value) @@ -41,16 +40,13 @@ public void BindParameterValue(DbParameter parameter, object? value) case Enum enumValue: parameter.DbType = DbConnectionPlusConfiguration.Instance.EnumSerializationMode switch { - EnumSerializationMode.Integers => - DbType.Int32, + EnumSerializationMode.Integers => DbType.Int32, - EnumSerializationMode.Strings => - DbType.String, + EnumSerializationMode.Strings => DbType.String, - _ => - ThrowHelper.ThrowInvalidEnumSerializationModeException( - DbConnectionPlusConfiguration.Instance.EnumSerializationMode - ) + _ => ThrowHelper.ThrowInvalidEnumSerializationModeException( + DbConnectionPlusConfiguration.Instance.EnumSerializationMode + ), }; parameter.Value = EnumSerializer.SerializeEnum( @@ -71,8 +67,7 @@ public void BindParameterValue(DbParameter parameter, object? value) } /// - public string FormatParameterName(string parameterName) => - "@" + parameterName; + public string FormatParameterName(string parameterName) => "@" + parameterName; /// public string GetDataType(Type type, EnumSerializationMode enumSerializationMode) @@ -86,14 +81,11 @@ public string GetDataType(Type type, EnumSerializationMode enumSerializationMode { return enumSerializationMode switch { - EnumSerializationMode.Strings => - "TEXT", + EnumSerializationMode.Strings => "TEXT", - EnumSerializationMode.Integers => - "INTEGER", + EnumSerializationMode.Integers => "INTEGER", - _ => - ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode) + _ => ThrowHelper.ThrowInvalidEnumSerializationModeException(enumSerializationMode), }; } @@ -110,16 +102,13 @@ public string GetDataType(Type type, EnumSerializationMode enumSerializationMode } /// - public string QuoteIdentifier(string identifier) => - "\"" + identifier + "\""; + public string QuoteIdentifier(string identifier) => "\"" + identifier + "\""; /// - public string QuoteTemporaryTableName(string tableName, DbConnection connection) => - "temp.\"" + tableName + "\""; + public string QuoteTemporaryTableName(string tableName, DbConnection connection) => "temp.\"" + tableName + "\""; /// - public bool SupportsTemporaryTables(DbConnection connection) => - true; + public bool SupportsTemporaryTables(DbConnection connection) => true; /// public bool WasSqlStatementCancelledByCancellationToken(Exception exception, CancellationToken cancellationToken) @@ -151,6 +140,6 @@ public bool WasSqlStatementCancelledByCancellationToken(Exception exception, Can { typeof(float), "REAL" }, { typeof(string), "TEXT" }, { typeof(TimeOnly), "TEXT" }, - { typeof(TimeSpan), "TEXT" } + { typeof(TimeSpan), "TEXT" }, }; } diff --git a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteEntityManipulator.cs index cdd56f8..2e216a1 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteEntityManipulator.cs @@ -15,9 +15,7 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.Sqlite; internal class SqliteEntityManipulator(SqliteDatabaseAdapter databaseAdapter) : IEntityManipulator { /// - public int DeleteEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int DeleteEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -64,11 +62,8 @@ CancellationToken cancellationToken totalNumberOfAffectedRows += numberOfAffectedRows; } } - catch (Exception exception) when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -78,9 +73,7 @@ CancellationToken cancellationToken } /// - public async Task DeleteEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task DeleteEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -113,8 +106,9 @@ CancellationToken cancellationToken DbConnectionExtensions.OnBeforeExecutingCommand(command, []); - var numberOfAffectedRows = - await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false); + var numberOfAffectedRows = await command + .ExecuteNonQueryAsync(cancellationToken) + .ConfigureAwait(false); if (numberOfAffectedRows != 1) { @@ -128,11 +122,8 @@ CancellationToken cancellationToken totalNumberOfAffectedRows += numberOfAffectedRows; } } - catch (Exception exception) when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -142,9 +133,7 @@ CancellationToken cancellationToken } /// - public int DeleteEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int DeleteEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -181,11 +170,8 @@ CancellationToken cancellationToken return numberOfAffectedRows; } - catch (Exception exception) when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -193,9 +179,7 @@ CancellationToken cancellationToken } /// - public async Task DeleteEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task DeleteEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -232,11 +216,8 @@ CancellationToken cancellationToken return numberOfAffectedRows; } - catch (Exception exception) when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -244,9 +225,7 @@ CancellationToken cancellationToken } /// - public int InsertEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int InsertEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -258,11 +237,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateInsertEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateInsertEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -290,9 +265,8 @@ CancellationToken cancellationToken totalNumberOfAffectedRows += reader.RecordsAffected; } } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -302,9 +276,7 @@ CancellationToken cancellationToken } /// - public async Task InsertEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task InsertEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -316,11 +288,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateInsertEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateInsertEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -343,22 +311,18 @@ CancellationToken cancellationToken #pragma warning disable CA2007 await using var reader = await command - .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken).ConfigureAwait(false); + .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken) + .ConfigureAwait(false); #pragma warning restore CA2007 - await UpdateDatabaseGeneratedPropertiesAsync( - entityTypeMetadata, - reader, - entity, - cancellationToken - ).ConfigureAwait(false); + await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, cancellationToken) + .ConfigureAwait(false); totalNumberOfAffectedRows += reader.RecordsAffected; } } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -368,9 +332,7 @@ await UpdateDatabaseGeneratedPropertiesAsync( } /// - public int InsertEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int InsertEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -382,11 +344,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateInsertEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateInsertEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -404,9 +362,8 @@ CancellationToken cancellationToken return reader.RecordsAffected; } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -414,9 +371,7 @@ CancellationToken cancellationToken } /// - public async Task InsertEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task InsertEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -428,11 +383,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateInsertEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateInsertEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -446,7 +397,8 @@ CancellationToken cancellationToken #pragma warning disable CA2007 await using var reader = await command - .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken).ConfigureAwait(false); + .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken) + .ConfigureAwait(false); #pragma warning restore CA2007 await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, cancellationToken) @@ -454,9 +406,8 @@ await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, return reader.RecordsAffected; } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -464,9 +415,7 @@ await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, } /// - public int UpdateEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int UpdateEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -478,11 +427,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateUpdateEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateUpdateEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -524,9 +469,8 @@ CancellationToken cancellationToken totalNumberOfAffectedRows += reader.RecordsAffected; } } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -536,9 +480,7 @@ CancellationToken cancellationToken } /// - public async Task UpdateEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task UpdateEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -550,11 +492,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateUpdateEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateUpdateEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -577,15 +515,12 @@ CancellationToken cancellationToken #pragma warning disable CA2007 await using var reader = await command - .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken).ConfigureAwait(false); + .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken) + .ConfigureAwait(false); #pragma warning restore CA2007 - await UpdateDatabaseGeneratedPropertiesAsync( - entityTypeMetadata, - reader, - entity, - cancellationToken - ).ConfigureAwait(false); + await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, cancellationToken) + .ConfigureAwait(false); // We must close the reader before we can access DbDataReader.RecordsAffected, because otherwise it // returns -1 when we select database generated properties via the SELECT statement after the @@ -604,9 +539,8 @@ await UpdateDatabaseGeneratedPropertiesAsync( totalNumberOfAffectedRows += reader.RecordsAffected; } } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -616,9 +550,7 @@ await UpdateDatabaseGeneratedPropertiesAsync( } /// - public int UpdateEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int UpdateEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -630,11 +562,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateUpdateEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateUpdateEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -666,9 +594,8 @@ CancellationToken cancellationToken return reader.RecordsAffected; } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -676,9 +603,7 @@ CancellationToken cancellationToken } /// - public async Task UpdateEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public async Task UpdateEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -690,11 +615,7 @@ CancellationToken cancellationToken var entityTypeMetadata = EntityHelper.GetEntityTypeMetadata(typeof(TEntity)); - var (command, parameters) = this.CreateUpdateEntityCommand( - connection, - transaction, - entityTypeMetadata - ); + var (command, parameters) = this.CreateUpdateEntityCommand(connection, transaction, entityTypeMetadata); var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); using (command) @@ -731,9 +652,8 @@ await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, return reader.RecordsAffected; } - catch (Exception exception) when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -765,8 +685,8 @@ EntityTypeMetadata entityTypeMetadata var parameters = new List(); - var whereProperties = entityTypeMetadata.KeyProperties - .Concat(entityTypeMetadata.ConcurrencyTokenProperties) + var whereProperties = entityTypeMetadata + .KeyProperties.Concat(entityTypeMetadata.ConcurrencyTokenProperties) .Concat(entityTypeMetadata.RowVersionProperties); foreach (var property in whereProperties) @@ -882,8 +802,8 @@ private string GetDeleteEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => var prependSeparator = false; - var whereProperties = entityTypeMetadata.KeyProperties - .Concat(entityTypeMetadata.ConcurrencyTokenProperties) + var whereProperties = entityTypeMetadata + .KeyProperties.Concat(entityTypeMetadata.ConcurrencyTokenProperties) .Concat(entityTypeMetadata.RowVersionProperties); foreach (var keyProperty in whereProperties) @@ -1092,8 +1012,8 @@ private string GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => prependSeparator = false; - var whereProperties = entityTypeMetadata.KeyProperties - .Concat(entityTypeMetadata.ConcurrencyTokenProperties) + var whereProperties = entityTypeMetadata + .KeyProperties.Concat(entityTypeMetadata.ConcurrencyTokenProperties) .Concat(entityTypeMetadata.RowVersionProperties) .ToList(); @@ -1157,7 +1077,7 @@ private string GetUpdateEntitySqlCode(EntityTypeMetadata entityTypeMetadata) => whereProperties = [ .. entityTypeMetadata.KeyProperties, - .. entityTypeMetadata.ConcurrencyTokenProperties + .. entityTypeMetadata.ConcurrencyTokenProperties, ]; foreach (var keyProperty in whereProperties) @@ -1259,8 +1179,8 @@ CancellationToken cancellationToken ) { if ( - entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 && - await reader.ReadAsync(cancellationToken).ConfigureAwait(false) + entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 + && await reader.ReadAsync(cancellationToken).ConfigureAwait(false) ) { for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) diff --git a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteTemporaryTableBuilder.cs b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteTemporaryTableBuilder.cs index 4138d47..f6d4a30 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteTemporaryTableBuilder.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteTemporaryTableBuilder.cs @@ -36,8 +36,7 @@ public TemporaryTableDisposer BuildTemporaryTable( DbTransaction? transaction, string name, IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, CancellationToken cancellationToken = default ) { @@ -69,8 +68,10 @@ public TemporaryTableDisposer BuildTemporaryTable( ); createCommand.Transaction = transaction; - using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken); + using var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation( + createCommand, + cancellationToken + ); DbConnectionExtensions.OnBeforeExecutingCommand(createCommand, []); @@ -87,8 +88,10 @@ public TemporaryTableDisposer BuildTemporaryTable( ); createCommand.Transaction = transaction; - using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken); + using var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation( + createCommand, + cancellationToken + ); DbConnectionExtensions.OnBeforeExecutingCommand(createCommand, []); @@ -111,8 +114,7 @@ public async Task BuildTemporaryTableAsync( DbTransaction? transaction, string name, IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, CancellationToken cancellationToken = default ) { @@ -146,8 +148,9 @@ public async Task BuildTemporaryTableAsync( ); createCommand.Transaction = transaction; - await using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken).ConfigureAwait(false); + await using var cancellationTokenRegistration = DbCommandHelper + .RegisterDbCommandCancellation(createCommand, cancellationToken) + .ConfigureAwait(false); DbConnectionExtensions.OnBeforeExecutingCommand(createCommand, []); @@ -166,8 +169,9 @@ public async Task BuildTemporaryTableAsync( ); createCommand.Transaction = transaction; - await using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(createCommand, cancellationToken).ConfigureAwait(false); + await using var cancellationTokenRegistration = DbCommandHelper + .RegisterDbCommandCancellation(createCommand, cancellationToken) + .ConfigureAwait(false); DbConnectionExtensions.OnBeforeExecutingCommand(createCommand, []); @@ -204,8 +208,7 @@ await PopulateTemporaryTableAsync( /// The built SQL code. private string BuildCreateMultiColumnTemporaryTableSqlCode( string tableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type objectsType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type objectsType, EnumSerializationMode enumSerializationMode ) { @@ -255,8 +258,7 @@ EnumSerializationMode enumSerializationMode /// The built SQL code. private string BuildCreateSingleColumnTemporaryTableSqlCode( string tableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, EnumSerializationMode enumSerializationMode ) { @@ -285,8 +287,7 @@ EnumSerializationMode enumSerializationMode /// A tuple containing the insert SQL code and the parameters to use. private static (string SqlCode, SqliteParameter[] Parameters) BuildInsertSqlCode( string tableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, DbDataReader dataReader ) { @@ -306,14 +307,13 @@ DbDataReader dataReader { sqlBuilder.Append(Constants.SingleColumnTemporaryTableColumnName); - parameters[0] = new() - { - ParameterName = Constants.SingleColumnTemporaryTableColumnName - }; + parameters[0] = new() { ParameterName = Constants.SingleColumnTemporaryTableColumnName }; } else { - var properties = EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a.CanRead) + var properties = EntityHelper + .GetEntityTypeMetadata(valuesType) + .MappedProperties.Where(a => a.CanRead) .ToList(); for (var i = 0; i < properties.Count; i++) @@ -329,10 +329,7 @@ DbDataReader dataReader sqlBuilder.Append(property.ColumnName); sqlBuilder.Append('"'); - parameters[i] = new() - { - ParameterName = property.PropertyName - }; + parameters[i] = new() { ParameterName = property.PropertyName }; } } @@ -367,8 +364,8 @@ DbDataReader dataReader /// A that provides access to the data in . private static EnumerableReader CreateValuesDataReader( IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType) + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType + ) { if (valuesType.IsBuiltInTypeOrNullableBuiltInType() || valuesType.IsEnumOrNullableEnumType()) { @@ -438,8 +435,7 @@ private static void PopulateTemporaryTable( SqliteConnection connection, SqliteTransaction? transaction, string tableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, DbDataReader dataReader, CancellationToken cancellationToken ) @@ -494,8 +490,7 @@ private static async Task PopulateTemporaryTableAsync( SqliteConnection connection, SqliteTransaction? transaction, string tableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, DbDataReader dataReader, CancellationToken cancellationToken ) diff --git a/src/DbConnectionPlus/Configuration/DbConnectionPlusConfiguration.cs b/src/DbConnectionPlus/Configuration/DbConnectionPlusConfiguration.cs index ae151ee..609fa7b 100644 --- a/src/DbConnectionPlus/Configuration/DbConnectionPlusConfiguration.cs +++ b/src/DbConnectionPlus/Configuration/DbConnectionPlusConfiguration.cs @@ -8,9 +8,7 @@ public sealed class DbConnectionPlusConfiguration : IFreezable /// /// Initializes a new instance of the class. /// - internal DbConnectionPlusConfiguration() - { - } + internal DbConnectionPlusConfiguration() { } /// /// @@ -158,11 +156,11 @@ internal IDatabaseAdapter GetDatabaseAdapter(Type connectionType) return this.databaseAdapters.TryGetValue(connectionType, out var adapter) ? adapter : throw new InvalidOperationException( - $"No database adapter is registered for the database connection of the type {connectionType}. " + - "Please install the corresponding adapter NuGet package " + - "(e.g., RentADeveloper.DbConnectionPlus.DatabaseAdapters.SqlServer) " + - "and register it by calling the appropriate UseXxx() extension method via " + - $"{nameof(DbConnectionExtensions)}.{nameof(DbConnectionExtensions.Configure)}." + $"No database adapter is registered for the database connection of the type {connectionType}. " + + "Please install the corresponding adapter NuGet package " + + "(e.g., RentADeveloper.DbConnectionPlus.DatabaseAdapters.SqlServer) " + + "and register it by calling the appropriate UseXxx() extension method via " + + $"{nameof(DbConnectionExtensions)}.{nameof(DbConnectionExtensions.Configure)}." ); } diff --git a/src/DbConnectionPlus/Configuration/EntityPropertyBuilder.cs b/src/DbConnectionPlus/Configuration/EntityPropertyBuilder.cs index b2987a3..e262293 100644 --- a/src/DbConnectionPlus/Configuration/EntityPropertyBuilder.cs +++ b/src/DbConnectionPlus/Configuration/EntityPropertyBuilder.cs @@ -101,17 +101,16 @@ public EntityPropertyBuilder IsIdentity() { this.EnsureNotFrozen(); - var otherIdentityProperty = - this.entityTypeBuilder.PropertyBuilders.Values.FirstOrDefault(a => - a.PropertyName != this.propertyName && a.IsIdentity - ); + var otherIdentityProperty = this.entityTypeBuilder.PropertyBuilders.Values.FirstOrDefault(a => + a.PropertyName != this.propertyName && a.IsIdentity + ); if (otherIdentityProperty is not null) { throw new InvalidOperationException( - $"There is already the property '{otherIdentityProperty.PropertyName}' marked as an identity " + - $"property for the entity type {this.entityTypeBuilder.EntityType}. Only one property can be marked " + - "as identity property per entity type." + $"There is already the property '{otherIdentityProperty.PropertyName}' marked as an identity " + + $"property for the entity type {this.entityTypeBuilder.EntityType}. Only one property can be marked " + + "as identity property per entity type." ); } diff --git a/src/DbConnectionPlus/Configuration/EntityTypeBuilder.cs b/src/DbConnectionPlus/Configuration/EntityTypeBuilder.cs index 6434131..e9ff601 100644 --- a/src/DbConnectionPlus/Configuration/EntityTypeBuilder.cs +++ b/src/DbConnectionPlus/Configuration/EntityTypeBuilder.cs @@ -34,11 +34,12 @@ public EntityPropertyBuilder Property(Expression new EntityPropertyBuilder(self, propertyName2), - this - ); + return (EntityPropertyBuilder) + this.propertyBuilders.GetOrAdd( + propertyName, + static (propertyName2, self) => new EntityPropertyBuilder(self, propertyName2), + this + ); } /// @@ -74,8 +75,7 @@ void IFreezable.Freeze() } /// - IReadOnlyDictionary IEntityTypeBuilder.PropertyBuilders => - this.propertyBuilders; + IReadOnlyDictionary IEntityTypeBuilder.PropertyBuilders => this.propertyBuilders; /// string? IEntityTypeBuilder.TableName => this.tableName; @@ -104,8 +104,8 @@ private static string GetPropertyNameFromPropertyExpression(LambdaExpression pro propertyExpression.Body is MemberExpression { Member: PropertyInfo propertyInfo } ? propertyInfo.Name : throw new ArgumentException( - $"The expression '{propertyExpression}' is not a valid property access expression. The expression should " + - "represent a simple property access: 'a => a.MyProperty'.", + $"The expression '{propertyExpression}' is not a valid property access expression. The expression should " + + "represent a simple property access: 'a => a.MyProperty'.", nameof(propertyExpression) ); diff --git a/src/DbConnectionPlus/Converters/EnumConverter.cs b/src/DbConnectionPlus/Converters/EnumConverter.cs index 3d4637a..45bce3e 100644 --- a/src/DbConnectionPlus/Converters/EnumConverter.cs +++ b/src/DbConnectionPlus/Converters/EnumConverter.cs @@ -99,7 +99,8 @@ internal static class EnumConverter case null or DBNull when default(TTarget) is null: return default; - case null or DBNull when default(TTarget) is not null: + case null + or DBNull when default(TTarget) is not null: ThrowCouldNotConvertNullToNonNullableEnumTypeException(targetType); return default; // Just to satisfy the compiler. @@ -118,7 +119,17 @@ internal static class EnumConverter return (TTarget?)result; - case byte or sbyte or short or ushort or int or uint or long or ulong or double or float or decimal: + case byte + or sbyte + or short + or ushort + or int + or uint + or long + or ulong + or double + or float + or decimal: var enumUnderlyingType = Enum.GetUnderlyingType(effectiveTargetType); var valueConvertedToEnumUnderlyingType = Convert.ChangeType( @@ -132,16 +143,10 @@ internal static class EnumConverter ThrowCouldNotConvertNumericValueToEnumType(value, targetType); } - return (TTarget?)Enum.ToObject( - effectiveTargetType, - valueConvertedToEnumUnderlyingType - ); + return (TTarget?)Enum.ToObject(effectiveTargetType, valueConvertedToEnumUnderlyingType); default: - ThrowValueIsNeitherEnumValueNorStringNorNumericValueException( - value, - targetType - ); + ThrowValueIsNeitherEnumValueNorStringNorNumericValueException(value, targetType); return default; // Just to satisfy the compiler. } } @@ -235,7 +240,8 @@ internal static class EnumConverter case null or DBNull when targetType.IsReferenceTypeOrNullableType(): return null; - case null or DBNull when !targetType.IsReferenceTypeOrNullableType(): + case null + or DBNull when !targetType.IsReferenceTypeOrNullableType(): ThrowCouldNotConvertNullToNonNullableEnumTypeException(targetType); return null; // Just to satisfy the compiler. @@ -254,7 +260,17 @@ internal static class EnumConverter return result; - case byte or sbyte or short or ushort or int or uint or long or ulong or double or float or decimal: + case byte + or sbyte + or short + or ushort + or int + or uint + or long + or ulong + or double + or float + or decimal: var enumUnderlyingType = Enum.GetUnderlyingType(effectiveTargetType); var valueConvertedToEnumUnderlyingType = Convert.ChangeType( @@ -268,16 +284,10 @@ internal static class EnumConverter ThrowCouldNotConvertNumericValueToEnumType(value, targetType); } - return Enum.ToObject( - effectiveTargetType, - valueConvertedToEnumUnderlyingType - ); + return Enum.ToObject(effectiveTargetType, valueConvertedToEnumUnderlyingType); default: - ThrowValueIsNeitherEnumValueNorStringNorNumericValueException( - value, - targetType - ); + ThrowValueIsNeitherEnumValueNorStringNorNumericValueException(value, targetType); return null; // Just to satisfy the compiler. } } @@ -286,43 +296,37 @@ internal static class EnumConverter [DoesNotReturn] private static void ThrowCouldNotConvertEmptyOrWhitespaceStringToEnumTypeException(Type enumType) => throw new InvalidCastException( - "Could not convert an empty string or a string that consists only of white-space characters to an enum " + - $"member of the type {enumType}." + "Could not convert an empty string or a string that consists only of white-space characters to an enum " + + $"member of the type {enumType}." ); [MethodImpl(MethodImplOptions.NoInlining)] [DoesNotReturn] private static void ThrowCouldNotConvertNullToNonNullableEnumTypeException(Type enumType) => - throw new InvalidCastException( - $"Could not convert {{null}} to an enum member of the type {enumType}." - ); + throw new InvalidCastException($"Could not convert {{null}} to an enum member of the type {enumType}."); [MethodImpl(MethodImplOptions.NoInlining)] [DoesNotReturn] - private static void - ThrowCouldNotConvertNumericValueToEnumType(object value, Type enumType) => + private static void ThrowCouldNotConvertNumericValueToEnumType(object value, Type enumType) => throw new InvalidCastException( - $"Could not convert the value {value.ToDebugString()} to an enum member of the type {enumType}. That " + - "value does not match any of the values of the enum's members." + $"Could not convert the value {value.ToDebugString()} to an enum member of the type {enumType}. That " + + "value does not match any of the values of the enum's members." ); [MethodImpl(MethodImplOptions.NoInlining)] [DoesNotReturn] - private static void ThrowCouldNotConvertStringToEnumTypeException( - string value, - Type enumType - ) => + private static void ThrowCouldNotConvertStringToEnumTypeException(string value, Type enumType) => throw new InvalidCastException( - $"Could not convert the string '{value}' to an enum member of the type {enumType}. That string does " + - "not match any of the names of the enum's members." + $"Could not convert the string '{value}' to an enum member of the type {enumType}. That string does " + + "not match any of the names of the enum's members." ); [MethodImpl(MethodImplOptions.NoInlining)] [DoesNotReturn] private static void ThrowTypeIsNeitherEnumNorNullableEnumTypeException(object? value, Type enumType) => throw new ArgumentException( - $"Could not convert the value {value.ToDebugString()} to an enum member of the type {enumType}, because " + - $"the type {enumType} is not an enum type.", + $"Could not convert the value {value.ToDebugString()} to an enum member of the type {enumType}, because " + + $"the type {enumType} is not an enum type.", nameof(enumType) ); @@ -333,7 +337,7 @@ private static void ThrowValueIsNeitherEnumValueNorStringNorNumericValueExceptio Type originalEnumType ) => throw new InvalidCastException( - $"Could not convert the value {value.ToDebugString()} to an enum member of the type {originalEnumType}. " + - "The value must either be an enum value of that type or a string or a numeric value." + $"Could not convert the value {value.ToDebugString()} to an enum member of the type {originalEnumType}. " + + "The value must either be an enum value of that type or a string or a numeric value." ); } diff --git a/src/DbConnectionPlus/Converters/EnumSerializer.cs b/src/DbConnectionPlus/Converters/EnumSerializer.cs index 99af75f..88f4cfa 100644 --- a/src/DbConnectionPlus/Converters/EnumSerializer.cs +++ b/src/DbConnectionPlus/Converters/EnumSerializer.cs @@ -27,14 +27,11 @@ internal static object SerializeEnum(Enum enumValue, EnumSerializationMode seria return serializationMode switch { - EnumSerializationMode.Strings => - enumValue.ToString(), + EnumSerializationMode.Strings => enumValue.ToString(), - EnumSerializationMode.Integers => - Convert.ToInt32(enumValue, CultureInfo.InvariantCulture), + EnumSerializationMode.Integers => Convert.ToInt32(enumValue, CultureInfo.InvariantCulture), - _ => - ThrowHelper.ThrowInvalidEnumSerializationModeException(serializationMode) + _ => ThrowHelper.ThrowInvalidEnumSerializationModeException(serializationMode), }; } } diff --git a/src/DbConnectionPlus/Converters/ValueConverter.cs b/src/DbConnectionPlus/Converters/ValueConverter.cs index afc6d4e..c1b9dc1 100644 --- a/src/DbConnectionPlus/Converters/ValueConverter.cs +++ b/src/DbConnectionPlus/Converters/ValueConverter.cs @@ -43,10 +43,7 @@ internal static bool CanConvert(Type sourceType, Type targetType) var effectiveSourceType = Nullable.GetUnderlyingType(sourceType) ?? sourceType; var effectiveTargetType = Nullable.GetUnderlyingType(targetType) ?? targetType; - if ( - effectiveSourceType == effectiveTargetType || - effectiveTargetType == typeof(object) - ) + if (effectiveSourceType == effectiveTargetType || effectiveTargetType == typeof(object)) { // Conversion to same type or to Object is always possible. return true; @@ -108,7 +105,8 @@ internal static bool CanConvert(Type sourceType, Type targetType) case null or DBNull when default(TTarget) is null: return default; - case null or DBNull when default(TTarget) is not null: + case null + or DBNull when default(TTarget) is not null: ThrowCouldNotConvertNullOrDbNullToNonNullableTargetTypeException(value, targetType); return default; // Just to satisfy the compiler. @@ -134,10 +132,7 @@ internal static bool CanConvert(Type sourceType, Type targetType) case string stringValue when effectiveTargetType == typeof(char): if (stringValue.Length != 1) { - ThrowCouldNotConvertNonSingleCharStringToCharException( - stringValue, - targetType - ); + ThrowCouldNotConvertNonSingleCharStringToCharException(stringValue, targetType); } return (TTarget)(object)stringValue[0]; @@ -204,21 +199,13 @@ internal static bool CanConvert(Type sourceType, Type targetType) try { - return (TTarget?)Convert.ChangeType( - value, - effectiveTargetType, - CultureInfo.InvariantCulture - ); + return (TTarget?)Convert.ChangeType(value, effectiveTargetType, CultureInfo.InvariantCulture); } - catch (Exception exception) when ( - exception is ArgumentException or InvalidCastException or FormatException or OverflowException - ) + catch (Exception exception) + when (exception is ArgumentException or InvalidCastException or FormatException or OverflowException + ) { - ThrowCouldNotConvertValueToTargetTypeException( - value, - targetType, - exception - ); + ThrowCouldNotConvertValueToTargetTypeException(value, targetType, exception); return default; // Just to satisfy the compiler } } @@ -268,7 +255,8 @@ exception is ArgumentException or InvalidCastException or FormatException or Ove case null or DBNull when targetType.IsReferenceTypeOrNullableType(): return null; - case null or DBNull when !targetType.IsReferenceTypeOrNullableType(): + case null + or DBNull when !targetType.IsReferenceTypeOrNullableType(): ThrowCouldNotConvertNullOrDbNullToNonNullableTargetTypeException(value, targetType); return null; // Just to satisfy the compiler. @@ -294,10 +282,7 @@ exception is ArgumentException or InvalidCastException or FormatException or Ove case string stringValue when effectiveTargetType == typeof(char): if (stringValue.Length != 1) { - ThrowCouldNotConvertNonSingleCharStringToCharException( - stringValue, - targetType - ); + ThrowCouldNotConvertNonSingleCharStringToCharException(stringValue, targetType); } return stringValue[0]; @@ -364,15 +349,11 @@ exception is ArgumentException or InvalidCastException or FormatException or Ove try { - return Convert.ChangeType( - value, - effectiveTargetType, - CultureInfo.InvariantCulture - ); + return Convert.ChangeType(value, effectiveTargetType, CultureInfo.InvariantCulture); } - catch (Exception exception) when ( - exception is ArgumentException or InvalidCastException or FormatException or OverflowException - ) + catch (Exception exception) + when (exception is ArgumentException or InvalidCastException or FormatException or OverflowException + ) { ThrowCouldNotConvertValueToTargetTypeException(value, targetType, exception); return null; // Just to satisfy the compiler @@ -390,27 +371,28 @@ exception is ArgumentException or InvalidCastException or FormatException or Ove /// that an enum can be converted to; otherwise, . /// private static bool IsSupportedEnumConversionType(Type type) => - Type.GetTypeCode(type) is - // Ordered by frequency of use: - TypeCode.String or - TypeCode.Int32 or - TypeCode.Int16 or - TypeCode.Int64 or - TypeCode.Double or - TypeCode.Single or - TypeCode.Decimal or - TypeCode.Byte or - TypeCode.SByte or - TypeCode.UInt16 or - TypeCode.UInt32 or - TypeCode.UInt64; + Type.GetTypeCode(type) + is + // Ordered by frequency of use: + TypeCode.String + or TypeCode.Int32 + or TypeCode.Int16 + or TypeCode.Int64 + or TypeCode.Double + or TypeCode.Single + or TypeCode.Decimal + or TypeCode.Byte + or TypeCode.SByte + or TypeCode.UInt16 + or TypeCode.UInt32 + or TypeCode.UInt64; [MethodImpl(MethodImplOptions.NoInlining)] [DoesNotReturn] private static void ThrowCouldNotConvertNonSingleCharStringToCharException(string stringValue, Type targetType) => throw new InvalidCastException( - $"Could not convert the string '{stringValue}' to the type {targetType}. The string must be exactly one " + - "character long." + $"Could not convert the string '{stringValue}' to the type {targetType}. The string must be exactly one " + + "character long." ); [MethodImpl(MethodImplOptions.NoInlining)] @@ -420,8 +402,8 @@ private static void ThrowCouldNotConvertNullOrDbNullToNonNullableTargetTypeExcep Type targetType ) => throw new InvalidCastException( - $"Could not convert the value {value.ToDebugString()} to the type {targetType}, because the type is " + - "non-nullable." + $"Could not convert the value {value.ToDebugString()} to the type {targetType}, because the type is " + + "non-nullable." ); [MethodImpl(MethodImplOptions.NoInlining)] @@ -432,17 +414,14 @@ private static void ThrowCouldNotConvertValueToTargetTypeException( Exception innerException ) => throw new InvalidCastException( - $"Could not convert the value {value.ToDebugString()} to the type {targetType}. See inner exception " + - "for details.", + $"Could not convert the value {value.ToDebugString()} to the type {targetType}. See inner exception " + + "for details.", innerException ); [MethodImpl(MethodImplOptions.NoInlining)] [DoesNotReturn] - private static void ThrowCouldNotConvertValueToTargetTypeException( - object? value, - Type targetType - ) => + private static void ThrowCouldNotConvertValueToTargetTypeException(object? value, Type targetType) => throw new InvalidCastException( $"Could not convert the value {value.ToDebugString()} to the type {targetType}. " ); @@ -462,7 +441,6 @@ Type targetType (typeof(bool), typeof(ushort)), (typeof(bool), typeof(uint)), (typeof(bool), typeof(ulong)), - (typeof(byte), typeof(bool)), (typeof(byte), typeof(byte)), (typeof(byte), typeof(char)), @@ -477,9 +455,7 @@ Type targetType (typeof(byte), typeof(ushort)), (typeof(byte), typeof(uint)), (typeof(byte), typeof(ulong)), - (typeof(byte[]), typeof(Guid)), - (typeof(char), typeof(byte)), (typeof(char), typeof(char)), (typeof(char), typeof(short)), @@ -490,17 +466,13 @@ Type targetType (typeof(char), typeof(ushort)), (typeof(char), typeof(uint)), (typeof(char), typeof(ulong)), - (typeof(DateOnly), typeof(DateOnly)), (typeof(DateOnly), typeof(string)), - (typeof(DateTime), typeof(DateTime)), (typeof(DateTime), typeof(DateOnly)), (typeof(DateTime), typeof(string)), - (typeof(DateTimeOffset), typeof(DateTimeOffset)), (typeof(DateTimeOffset), typeof(string)), - (typeof(decimal), typeof(bool)), (typeof(decimal), typeof(byte)), (typeof(decimal), typeof(decimal)), @@ -514,7 +486,6 @@ Type targetType (typeof(decimal), typeof(ushort)), (typeof(decimal), typeof(uint)), (typeof(decimal), typeof(ulong)), - (typeof(double), typeof(bool)), (typeof(double), typeof(byte)), (typeof(double), typeof(decimal)), @@ -528,11 +499,9 @@ Type targetType (typeof(double), typeof(ushort)), (typeof(double), typeof(uint)), (typeof(double), typeof(ulong)), - (typeof(Guid), typeof(byte[])), (typeof(Guid), typeof(Guid)), (typeof(Guid), typeof(string)), - (typeof(short), typeof(bool)), (typeof(short), typeof(byte)), (typeof(short), typeof(char)), @@ -547,7 +516,6 @@ Type targetType (typeof(short), typeof(ushort)), (typeof(short), typeof(uint)), (typeof(short), typeof(ulong)), - (typeof(int), typeof(bool)), (typeof(int), typeof(byte)), (typeof(int), typeof(char)), @@ -562,7 +530,6 @@ Type targetType (typeof(int), typeof(ushort)), (typeof(int), typeof(uint)), (typeof(int), typeof(ulong)), - (typeof(long), typeof(bool)), (typeof(long), typeof(byte)), (typeof(long), typeof(char)), @@ -577,9 +544,7 @@ Type targetType (typeof(long), typeof(ushort)), (typeof(long), typeof(uint)), (typeof(long), typeof(ulong)), - (typeof(IntPtr), typeof(IntPtr)), - (typeof(sbyte), typeof(bool)), (typeof(sbyte), typeof(byte)), (typeof(sbyte), typeof(char)), @@ -594,7 +559,6 @@ Type targetType (typeof(sbyte), typeof(ushort)), (typeof(sbyte), typeof(uint)), (typeof(sbyte), typeof(ulong)), - (typeof(float), typeof(bool)), (typeof(float), typeof(byte)), (typeof(float), typeof(decimal)), @@ -608,7 +572,6 @@ Type targetType (typeof(float), typeof(ushort)), (typeof(float), typeof(uint)), (typeof(float), typeof(ulong)), - (typeof(string), typeof(bool)), (typeof(string), typeof(byte)), (typeof(string), typeof(char)), @@ -629,14 +592,11 @@ Type targetType (typeof(string), typeof(ulong)), (typeof(string), typeof(TimeSpan)), (typeof(string), typeof(TimeOnly)), - (typeof(TimeOnly), typeof(TimeOnly)), (typeof(TimeOnly), typeof(string)), - (typeof(TimeSpan), typeof(TimeOnly)), (typeof(TimeSpan), typeof(TimeSpan)), (typeof(TimeSpan), typeof(string)), - (typeof(ushort), typeof(bool)), (typeof(ushort), typeof(byte)), (typeof(ushort), typeof(char)), @@ -651,7 +611,6 @@ Type targetType (typeof(ushort), typeof(ushort)), (typeof(ushort), typeof(uint)), (typeof(ushort), typeof(ulong)), - (typeof(uint), typeof(bool)), (typeof(uint), typeof(byte)), (typeof(uint), typeof(char)), @@ -666,7 +625,6 @@ Type targetType (typeof(uint), typeof(ushort)), (typeof(uint), typeof(uint)), (typeof(uint), typeof(ulong)), - (typeof(ulong), typeof(bool)), (typeof(ulong), typeof(byte)), (typeof(ulong), typeof(char)), @@ -681,7 +639,6 @@ Type targetType (typeof(ulong), typeof(ushort)), (typeof(ulong), typeof(uint)), (typeof(ulong), typeof(ulong)), - - (typeof(UIntPtr), typeof(UIntPtr)) + (typeof(UIntPtr), typeof(UIntPtr)), ]; } diff --git a/src/DbConnectionPlus/DatabaseAdapters/IDatabaseAdapter.cs b/src/DbConnectionPlus/DatabaseAdapters/IDatabaseAdapter.cs index 20758e1..9b28dd1 100644 --- a/src/DbConnectionPlus/DatabaseAdapters/IDatabaseAdapter.cs +++ b/src/DbConnectionPlus/DatabaseAdapters/IDatabaseAdapter.cs @@ -120,8 +120,5 @@ public interface IDatabaseAdapter /// ; otherwise, . /// /// is . - public bool WasSqlStatementCancelledByCancellationToken( - Exception exception, - CancellationToken cancellationToken - ); + public bool WasSqlStatementCancelledByCancellationToken(Exception exception, CancellationToken cancellationToken); } diff --git a/src/DbConnectionPlus/DatabaseAdapters/IEntityManipulator.cs b/src/DbConnectionPlus/DatabaseAdapters/IEntityManipulator.cs index 7e9dea0..b957dbc 100644 --- a/src/DbConnectionPlus/DatabaseAdapters/IEntityManipulator.cs +++ b/src/DbConnectionPlus/DatabaseAdapters/IEntityManipulator.cs @@ -56,15 +56,12 @@ public interface IEntityManipulator /// Use or to configure key properties. /// /// - public int DeleteEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int DeleteEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, CancellationToken cancellationToken - ) => - 0; + ) => 0; /// /// Asynchronously deletes the specified entities, identified by their key property/properties, from the database. @@ -114,9 +111,7 @@ CancellationToken cancellationToken /// Use or to configure key properties. /// /// - public Task DeleteEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public Task DeleteEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -168,15 +163,12 @@ CancellationToken cancellationToken /// Use or to configure key properties. /// /// - public int DeleteEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int DeleteEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, CancellationToken cancellationToken - ) => - 0; + ) => 0; /// /// Asynchronously deletes the specified entity, identified by its key property / properties, from the database. @@ -226,9 +218,7 @@ CancellationToken cancellationToken /// Use or to configure key properties. /// /// - public Task DeleteEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public Task DeleteEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -288,15 +278,12 @@ CancellationToken cancellationToken /// properties are updated accordingly. /// /// - public int InsertEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int InsertEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, CancellationToken cancellationToken - ) => - 0; + ) => 0; /// /// Asynchronously inserts the specified entities into the database. @@ -353,9 +340,7 @@ CancellationToken cancellationToken /// properties are updated accordingly. /// /// - public Task InsertEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public Task InsertEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -414,15 +399,12 @@ CancellationToken cancellationToken /// properties are updated accordingly. /// /// - public int InsertEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int InsertEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, CancellationToken cancellationToken - ) => - 0; + ) => 0; /// /// Asynchronously inserts the specified entity into the database. @@ -479,9 +461,7 @@ CancellationToken cancellationToken /// properties are updated accordingly. /// /// - public Task InsertEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public Task InsertEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, @@ -552,15 +532,12 @@ CancellationToken cancellationToken /// properties are updated accordingly. /// /// - public int UpdateEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int UpdateEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, CancellationToken cancellationToken - ) => - 0; + ) => 0; /// /// Asynchronously updates the specified entities, identified by their key property / properties, in the database. @@ -630,9 +607,7 @@ CancellationToken cancellationToken /// properties are updated accordingly. /// /// - public Task UpdateEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public Task UpdateEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, IEnumerable entities, DbTransaction? transaction, @@ -703,15 +678,12 @@ CancellationToken cancellationToken /// properties are updated accordingly. /// /// - public int UpdateEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public int UpdateEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, CancellationToken cancellationToken - ) => - 0; + ) => 0; /// /// Asynchronously updates the specified entity, identified by its key property / properties, in the database. @@ -780,9 +752,7 @@ CancellationToken cancellationToken /// properties are updated accordingly. /// /// - public Task UpdateEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public Task UpdateEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, TEntity entity, DbTransaction? transaction, diff --git a/src/DbConnectionPlus/DatabaseAdapters/ITemporaryTableBuilder.cs b/src/DbConnectionPlus/DatabaseAdapters/ITemporaryTableBuilder.cs index b5bbead..4ee5c35 100644 --- a/src/DbConnectionPlus/DatabaseAdapters/ITemporaryTableBuilder.cs +++ b/src/DbConnectionPlus/DatabaseAdapters/ITemporaryTableBuilder.cs @@ -82,8 +82,7 @@ public TemporaryTableDisposer BuildTemporaryTable( DbTransaction? transaction, string name, IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, CancellationToken cancellationToken = default ); @@ -163,8 +162,7 @@ public Task BuildTemporaryTableAsync( DbTransaction? transaction, string name, IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type valuesType, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, CancellationToken cancellationToken = default ); } diff --git a/src/DbConnectionPlus/DbCommands/DbCommandBuilder.cs b/src/DbConnectionPlus/DbCommands/DbCommandBuilder.cs index b41d422..90ae060 100644 --- a/src/DbConnectionPlus/DbCommands/DbCommandBuilder.cs +++ b/src/DbConnectionPlus/DbCommands/DbCommandBuilder.cs @@ -149,12 +149,13 @@ internal static (DbCommand, DbCommandDisposer) BuildDbCommand( if (statement.TemporaryTables.Count > 0) { temporaryTableDisposers = await BuildTemporaryTablesAsync( - statement.TemporaryTables, - databaseAdapter, - connection, - transaction, - cancellationToken - ).ConfigureAwait(false); + statement.TemporaryTables, + databaseAdapter, + connection, + transaction, + cancellationToken + ) + .ConfigureAwait(false); } return (command, new(command, temporaryTableDisposers, cancellationTokenRegistration)); @@ -215,39 +216,38 @@ private static (DbCommand, CancellationTokenRegistration) BuildDbCommandCore( break; case InterpolatedParameter interpolatedParameter: - { - var parameterName = interpolatedParameter.InferredName ?? - "Parameter_" + (parameterCount + 1); + { + var parameterName = interpolatedParameter.InferredName ?? "Parameter_" + (parameterCount + 1); - if (!parameterNameOccurrences.TryAdd(parameterName, 1)) - { - // Parameter name is already used, so we append a suffix to make it unique. - var count = ++parameterNameOccurrences[parameterName]; - parameterName += count; - } + if (!parameterNameOccurrences.TryAdd(parameterName, 1)) + { + // Parameter name is already used, so we append a suffix to make it unique. + var count = ++parameterNameOccurrences[parameterName]; + parameterName += count; + } - var dbParameter = command.CreateParameter(); - dbParameter.ParameterName = parameterName; - databaseAdapter.BindParameterValue(dbParameter, interpolatedParameter.Value); - dbParameters.Add(dbParameter); + var dbParameter = command.CreateParameter(); + dbParameter.ParameterName = parameterName; + databaseAdapter.BindParameterValue(dbParameter, interpolatedParameter.Value); + dbParameters.Add(dbParameter); - codeBuilder.Append(databaseAdapter.FormatParameterName(parameterName)); + codeBuilder.Append(databaseAdapter.FormatParameterName(parameterName)); - parameterCount++; - break; - } + parameterCount++; + break; + } case Parameter parameter: - { - var dbParameter = command.CreateParameter(); - dbParameter.ParameterName = parameter.Name; - databaseAdapter.BindParameterValue(dbParameter, parameter.Value); - dbParameters.Add(dbParameter); - - parameterNameOccurrences[parameter.Name] = 1; - parameterCount++; - break; - } + { + var dbParameter = command.CreateParameter(); + dbParameter.ParameterName = parameter.Name; + databaseAdapter.BindParameterValue(dbParameter, parameter.Value); + dbParameters.Add(dbParameter); + + parameterNameOccurrences[parameter.Name] = 1; + parameterCount++; + break; + } case InterpolatedTemporaryTable interpolatedTemporaryTable: codeBuilder.Append( @@ -313,9 +313,8 @@ CancellationToken cancellationToken ); } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { foreach (var temporaryTableDisposer in temporaryTableDisposers) { @@ -368,19 +367,20 @@ CancellationToken cancellationToken { var interpolatedTemporaryTable = temporaryTables[i]; - temporaryTableDisposers[i] = await databaseAdapter.TemporaryTableBuilder.BuildTemporaryTableAsync( - connection, - transaction, - interpolatedTemporaryTable.Name, - interpolatedTemporaryTable.Values, - interpolatedTemporaryTable.ValuesType, - cancellationToken - ).ConfigureAwait(false); + temporaryTableDisposers[i] = await databaseAdapter + .TemporaryTableBuilder.BuildTemporaryTableAsync( + connection, + transaction, + interpolatedTemporaryTable.Name, + interpolatedTemporaryTable.Values, + interpolatedTemporaryTable.ValuesType, + cancellationToken + ) + .ConfigureAwait(false); } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { foreach (var temporaryTableDisposer in temporaryTableDisposers) { diff --git a/src/DbConnectionPlus/DbConnectionExtensions.Configuration.cs b/src/DbConnectionPlus/DbConnectionExtensions.Configuration.cs index 1885b51..ccf9468 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.Configuration.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.Configuration.cs @@ -44,8 +44,7 @@ public static void Configure(Action configureActi internal static void OnBeforeExecutingCommand( DbCommand command, IReadOnlyList temporaryTables - ) => - DbConnectionPlusConfiguration.Instance.InterceptDbCommand?.Invoke(command, temporaryTables); + ) => DbConnectionPlusConfiguration.Instance.InterceptDbCommand?.Invoke(command, temporaryTables); private static readonly object configurationLockObject = new(); } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.DeleteEntities.cs b/src/DbConnectionPlus/DbConnectionExtensions.DeleteEntities.cs index ad4331a..307037a 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.DeleteEntities.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.DeleteEntities.cs @@ -58,20 +58,18 @@ public static partial class DbConnectionExtensions /// /// /// using static RentADeveloper.DbConnectionPlus.DbConnectionExtensions; - /// + /// /// class Product /// { /// [Key] /// public Int64 Id { get; set; } /// public Boolean IsDiscontinued { get; set; } /// } - /// + /// /// connection.DeleteEntities(products.Where(a => a.IsDiscontinued)); /// /// - public static int DeleteEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public static int DeleteEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( this DbConnection connection, IEnumerable entities, DbTransaction? transaction = null, @@ -84,12 +82,7 @@ public static int DeleteEntities< var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - return databaseAdapter.EntityManipulator.DeleteEntities( - connection, - entities, - transaction, - cancellationToken - ); + return databaseAdapter.EntityManipulator.DeleteEntities(connection, entities, transaction, cancellationToken); } /// @@ -143,20 +136,18 @@ public static int DeleteEntities< /// /// /// using static RentADeveloper.DbConnectionPlus.DbConnectionExtensions; - /// + /// /// class Product /// { /// [Key] /// public Int64 Id { get; set; } /// public Boolean IsDiscontinued { get; set; } /// } - /// + /// /// await connection.DeleteEntitiesAsync(products.Where(a => a.IsDiscontinued)); /// /// - public static Task DeleteEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public static Task DeleteEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( this DbConnection connection, IEnumerable entities, DbTransaction? transaction = null, @@ -169,7 +160,11 @@ public static Task DeleteEntitiesAsync< var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - return databaseAdapter.EntityManipulator - .DeleteEntitiesAsync(connection, entities, transaction, cancellationToken); + return databaseAdapter.EntityManipulator.DeleteEntitiesAsync( + connection, + entities, + transaction, + cancellationToken + ); } } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.DeleteEntity.cs b/src/DbConnectionPlus/DbConnectionExtensions.DeleteEntity.cs index af10cdb..b8c0221 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.DeleteEntity.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.DeleteEntity.cs @@ -58,23 +58,21 @@ public static partial class DbConnectionExtensions /// /// /// using static RentADeveloper.DbConnectionPlus.DbConnectionExtensions; - /// + /// /// class Product /// { /// [Key] /// public Int64 Id { get; set; } /// public Boolean IsDiscontinued { get; set; } /// } - /// + /// /// if (product.IsDiscontinued) /// { /// connection.DeleteEntity(product); /// } /// /// - public static int DeleteEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public static int DeleteEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( this DbConnection connection, TEntity entity, DbTransaction? transaction = null, @@ -87,12 +85,7 @@ public static int DeleteEntity< var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - return databaseAdapter.EntityManipulator.DeleteEntity( - connection, - entity, - transaction, - cancellationToken - ); + return databaseAdapter.EntityManipulator.DeleteEntity(connection, entity, transaction, cancellationToken); } /// @@ -146,23 +139,21 @@ public static int DeleteEntity< /// /// /// using static RentADeveloper.DbConnectionPlus.DbConnectionExtensions; - /// + /// /// class Product /// { /// [Key] /// public Int64 Id { get; set; } /// public Boolean IsDiscontinued { get; set; } /// } - /// + /// /// if (product.IsDiscontinued) /// { /// await connection.DeleteEntityAsync(product); /// } /// /// - public static Task DeleteEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public static Task DeleteEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( this DbConnection connection, TEntity entity, DbTransaction? transaction = null, @@ -175,11 +166,6 @@ public static Task DeleteEntityAsync< var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - return databaseAdapter.EntityManipulator.DeleteEntityAsync( - connection, - entity, - transaction, - cancellationToken - ); + return databaseAdapter.EntityManipulator.DeleteEntityAsync(connection, entity, transaction, cancellationToken); } } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.ExecuteNonQuery.cs b/src/DbConnectionPlus/DbConnectionExtensions.ExecuteNonQuery.cs index fa4e768..8d585f0 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.ExecuteNonQuery.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.ExecuteNonQuery.cs @@ -31,7 +31,7 @@ public static partial class DbConnectionExtensions /// /// /// using static RentADeveloper.DbConnectionPlus.DbConnectionExtensions; - /// + /// /// if (supplier.IsRetired) /// { /// var numberOfDeletedProducts = connection.ExecuteNonQuery( @@ -70,9 +70,8 @@ public static int ExecuteNonQuery( OnBeforeExecutingCommand(command, statement.TemporaryTables); return command.ExecuteNonQuery(); } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -103,7 +102,7 @@ public static int ExecuteNonQuery( /// /// /// using static RentADeveloper.DbConnectionPlus.DbConnectionExtensions; - /// + /// /// if (supplier.IsRetired) /// { /// var numberOfDeletedProducts = await connection.ExecuteNonQueryAsync( @@ -125,15 +124,17 @@ public static async Task ExecuteNonQueryAsync( var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - var (command, commandDisposer) = await DbCommandBuilder.BuildDbCommandAsync( - statement, - databaseAdapter, - connection, - transaction, - commandTimeout, - commandType, - cancellationToken - ).ConfigureAwait(false); + var (command, commandDisposer) = await DbCommandBuilder + .BuildDbCommandAsync( + statement, + databaseAdapter, + connection, + transaction, + commandTimeout, + commandType, + cancellationToken + ) + .ConfigureAwait(false); await using (commandDisposer) { @@ -142,9 +143,8 @@ public static async Task ExecuteNonQueryAsync( OnBeforeExecutingCommand(command, statement.TemporaryTables); return await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false); } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.ExecuteReader.cs b/src/DbConnectionPlus/DbConnectionExtensions.ExecuteReader.cs index 62489eb..cbdaa88 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.ExecuteReader.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.ExecuteReader.cs @@ -39,9 +39,9 @@ public static partial class DbConnectionExtensions /// /// /// ExecuteReaderAsync( var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - var (command, commandDisposer) = await DbCommandBuilder.BuildDbCommandAsync( - statement, - databaseAdapter, - connection, - transaction, - commandTimeout, - commandType, - cancellationToken - ).ConfigureAwait(false); + var (command, commandDisposer) = await DbCommandBuilder + .BuildDbCommandAsync( + statement, + databaseAdapter, + connection, + transaction, + commandTimeout, + commandType, + cancellationToken + ) + .ConfigureAwait(false); DbDataReader? dataReader = null; @@ -175,9 +176,8 @@ public static async Task ExecuteReaderAsync( cancellationToken ); } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { if (dataReader is not null) { diff --git a/src/DbConnectionPlus/DbConnectionExtensions.ExecuteScalar.cs b/src/DbConnectionPlus/DbConnectionExtensions.ExecuteScalar.cs index 424b1bc..8b9b347 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.ExecuteScalar.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.ExecuteScalar.cs @@ -47,9 +47,9 @@ public static partial class DbConnectionExtensions /// /// ( /// $"SELECT COUNT(*) FROM Product WHERE UnitsInStock < {Parameter(lowStockThreshold)}" /// ); @@ -90,12 +90,11 @@ public static TTarget ExecuteScalar( { null => default!, // If the result set is empty, we get null and must return default of TTarget. TTarget alreadyTargetTypeValue => alreadyTargetTypeValue, - _ => ConvertValueForExecuteScalar(value) + _ => ConvertValueForExecuteScalar(value), }; } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -139,9 +138,9 @@ public static TTarget ExecuteScalar( /// /// ( /// $"SELECT COUNT(*) FROM Product WHERE UnitsInStock < {Parameter(lowStockThreshold)}" /// ); @@ -161,15 +160,17 @@ public static async Task ExecuteScalarAsync( var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - var (command, commandDisposer) = await DbCommandBuilder.BuildDbCommandAsync( - statement, - databaseAdapter, - connection, - transaction, - commandTimeout, - commandType, - cancellationToken - ).ConfigureAwait(false); + var (command, commandDisposer) = await DbCommandBuilder + .BuildDbCommandAsync( + statement, + databaseAdapter, + connection, + transaction, + commandTimeout, + commandType, + cancellationToken + ) + .ConfigureAwait(false); await using (commandDisposer) { @@ -182,12 +183,11 @@ public static async Task ExecuteScalarAsync( { null => default!, // If the result set is empty, we get null and must return default of TTarget. TTarget alreadyTargetTypeValue => alreadyTargetTypeValue, - _ => ConvertValueForExecuteScalar(value) + _ => ConvertValueForExecuteScalar(value), }; } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -214,17 +214,17 @@ private static TTarget ConvertValueForExecuteScalar(object? value) catch (Exception exception) when (value is null or DBNull) { throw new InvalidCastException( - "The first column of the first row in the result set returned by the SQL statement contains a NULL " + - $"value, which could not be converted to the type {typeof(TTarget)}. See inner exception for details.", + "The first column of the first row in the result set returned by the SQL statement contains a NULL " + + $"value, which could not be converted to the type {typeof(TTarget)}. See inner exception for details.", exception ); } catch (Exception exception) when (value is not null) { throw new InvalidCastException( - "The first column of the first row in the result set returned by the SQL statement contains " + - $"the value {value.ToDebugString()}, which could not be converted to the type {typeof(TTarget)}. " + - "See inner exception for details.", + "The first column of the first row in the result set returned by the SQL statement contains " + + $"the value {value.ToDebugString()}, which could not be converted to the type {typeof(TTarget)}. " + + "See inner exception for details.", exception ); } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.Exists.cs b/src/DbConnectionPlus/DbConnectionExtensions.Exists.cs index 34db0ea..8df8fee 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.Exists.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.Exists.cs @@ -38,9 +38,9 @@ public static partial class DbConnectionExtensions /// /// /// ExistsAsync( var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - var (command, commandDisposer) = await DbCommandBuilder.BuildDbCommandAsync( - statement, - databaseAdapter, - connection, - transaction, - commandTimeout, - commandType, - cancellationToken - ).ConfigureAwait(false); + var (command, commandDisposer) = await DbCommandBuilder + .BuildDbCommandAsync( + statement, + databaseAdapter, + connection, + transaction, + commandTimeout, + commandType, + cancellationToken + ) + .ConfigureAwait(false); await using (commandDisposer) { @@ -154,17 +155,15 @@ public static async Task ExistsAsync( { OnBeforeExecutingCommand(command, statement.TemporaryTables); #pragma warning disable CA2007 - await using var reader = await command.ExecuteReaderAsync( - CommandBehavior.SingleResult | CommandBehavior.SingleRow, - cancellationToken - ).ConfigureAwait(false); + await using var reader = await command + .ExecuteReaderAsync(CommandBehavior.SingleResult | CommandBehavior.SingleRow, cancellationToken) + .ConfigureAwait(false); #pragma warning restore CA2007 return await reader.ReadAsync(cancellationToken).ConfigureAwait(false); } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.InsertEntities.cs b/src/DbConnectionPlus/DbConnectionExtensions.InsertEntities.cs index 89c63e5..c8dbe77 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.InsertEntities.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.InsertEntities.cs @@ -65,7 +65,7 @@ public static partial class DbConnectionExtensions /// /// /// using static RentADeveloper.DbConnectionPlus.DbConnectionExtensions; - /// + /// /// class Product /// { /// public Int64 Id { get; set; } @@ -74,15 +74,13 @@ public static partial class DbConnectionExtensions /// public Decimal UnitPrice { get; set; } /// public Int32 UnitsInStock { get; set; } /// } - /// + /// /// var newProducts = GetNewProducts(); - /// + /// /// connection.InsertEntities(newProducts); /// /// - public static int InsertEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public static int InsertEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( this DbConnection connection, IEnumerable entities, DbTransaction? transaction = null, @@ -95,12 +93,7 @@ public static int InsertEntities< var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - return databaseAdapter.EntityManipulator.InsertEntities( - connection, - entities, - transaction, - cancellationToken - ); + return databaseAdapter.EntityManipulator.InsertEntities(connection, entities, transaction, cancellationToken); } /// @@ -161,7 +154,7 @@ public static int InsertEntities< /// /// /// using static RentADeveloper.DbConnectionPlus.DbConnectionExtensions; - /// + /// /// class Product /// { /// public Int64 Id { get; set; } @@ -170,15 +163,13 @@ public static int InsertEntities< /// public Decimal UnitPrice { get; set; } /// public Int32 UnitsInStock { get; set; } /// } - /// + /// /// var newProducts = await GetNewProductsAsync(); - /// + /// /// await connection.InsertEntitiesAsync(newProducts); /// /// - public static Task InsertEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public static Task InsertEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( this DbConnection connection, IEnumerable entities, DbTransaction? transaction = null, @@ -191,12 +182,11 @@ public static Task InsertEntitiesAsync< var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - return databaseAdapter.EntityManipulator - .InsertEntitiesAsync( - connection, - entities, - transaction, - cancellationToken - ); + return databaseAdapter.EntityManipulator.InsertEntitiesAsync( + connection, + entities, + transaction, + cancellationToken + ); } } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.InsertEntity.cs b/src/DbConnectionPlus/DbConnectionExtensions.InsertEntity.cs index 38f2a01..011285d 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.InsertEntity.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.InsertEntity.cs @@ -65,7 +65,7 @@ public static partial class DbConnectionExtensions /// /// /// using static RentADeveloper.DbConnectionPlus.DbConnectionExtensions; - /// + /// /// class Product /// { /// public Int64 Id { get; set; } @@ -74,15 +74,13 @@ public static partial class DbConnectionExtensions /// public Decimal UnitPrice { get; set; } /// public Int32 UnitsInStock { get; set; } /// } - /// + /// /// var newProduct = GetNewProduct(); - /// + /// /// connection.InsertEntity(newProduct); /// /// - public static int InsertEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public static int InsertEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( this DbConnection connection, TEntity entity, DbTransaction? transaction = null, @@ -95,12 +93,7 @@ public static int InsertEntity< var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - return databaseAdapter.EntityManipulator.InsertEntity( - connection, - entity, - transaction, - cancellationToken - ); + return databaseAdapter.EntityManipulator.InsertEntity(connection, entity, transaction, cancellationToken); } /// @@ -161,7 +154,7 @@ public static int InsertEntity< /// /// /// using static RentADeveloper.DbConnectionPlus.DbConnectionExtensions; - /// + /// /// class Product /// { /// public Int64 Id { get; set; } @@ -170,15 +163,13 @@ public static int InsertEntity< /// public Decimal UnitPrice { get; set; } /// public Int32 UnitsInStock { get; set; } /// } - /// + /// /// var newProduct = await GetNewProductAsync(); - /// + /// /// await connection.InsertEntityAsync(newProduct); /// /// - public static Task InsertEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public static Task InsertEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( this DbConnection connection, TEntity entity, DbTransaction? transaction = null, @@ -191,11 +182,6 @@ public static Task InsertEntityAsync< var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - return databaseAdapter.EntityManipulator.InsertEntityAsync( - connection, - entity, - transaction, - cancellationToken - ); + return databaseAdapter.EntityManipulator.InsertEntityAsync(connection, entity, transaction, cancellationToken); } } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.Parameter.cs b/src/DbConnectionPlus/DbConnectionExtensions.Parameter.cs index 49ff748..d45c7d6 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.Parameter.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.Parameter.cs @@ -38,9 +38,9 @@ public static partial class DbConnectionExtensions /// /// public static InterpolatedParameter Parameter( object? parameterValue, - [CallerArgumentExpression(nameof(parameterValue))] - string? parameterValueExpression = null + [CallerArgumentExpression(nameof(parameterValue))] string? parameterValueExpression = null ) { string? inferredParameterName = null; diff --git a/src/DbConnectionPlus/DbConnectionExtensions.Query.cs b/src/DbConnectionPlus/DbConnectionExtensions.Query.cs index 45d986f..4321f1a 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.Query.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.Query.cs @@ -3,8 +3,8 @@ using RentADeveloper.DbConnectionPlus.Materializers; using RentADeveloper.DbConnectionPlus.SqlStatements; -using DbCommandBuilder = RentADeveloper.DbConnectionPlus.DbCommands.DbCommandBuilder; using DataRow = RentADeveloper.DbConnectionPlus.Dynamic.DataRow; +using DbCommandBuilder = RentADeveloper.DbConnectionPlus.DbCommands.DbCommandBuilder; namespace RentADeveloper.DbConnectionPlus; @@ -102,9 +102,8 @@ public static IEnumerable Query( OnBeforeExecutingCommand(command, statement.TemporaryTables); reader = command.ExecuteReader(CommandBehavior.SequentialAccess); } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { reader?.Dispose(); @@ -126,9 +125,8 @@ public static IEnumerable Query( yield break; } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -211,15 +209,17 @@ public static async IAsyncEnumerable QueryAsync( var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - var (command, commandDisposer) = await DbCommandBuilder.BuildDbCommandAsync( - statement, - databaseAdapter, - connection, - transaction, - commandTimeout, - commandType, - cancellationToken - ).ConfigureAwait(false); + var (command, commandDisposer) = await DbCommandBuilder + .BuildDbCommandAsync( + statement, + databaseAdapter, + connection, + transaction, + commandTimeout, + commandType, + cancellationToken + ) + .ConfigureAwait(false); await using (commandDisposer) { @@ -228,12 +228,12 @@ public static async IAsyncEnumerable QueryAsync( try { OnBeforeExecutingCommand(command, statement.TemporaryTables); - reader = await command.ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken) + reader = await command + .ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken) .ConfigureAwait(false); } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { if (reader is not null) { @@ -256,9 +256,8 @@ public static async IAsyncEnumerable QueryAsync( yield break; } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.QueryFirst.cs b/src/DbConnectionPlus/DbConnectionExtensions.QueryFirst.cs index 8f61c54..4f28566 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.QueryFirst.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.QueryFirst.cs @@ -3,8 +3,8 @@ using RentADeveloper.DbConnectionPlus.Materializers; using RentADeveloper.DbConnectionPlus.SqlStatements; -using DbCommandBuilder = RentADeveloper.DbConnectionPlus.DbCommands.DbCommandBuilder; using DataRow = RentADeveloper.DbConnectionPlus.Dynamic.DataRow; +using DbCommandBuilder = RentADeveloper.DbConnectionPlus.DbCommands.DbCommandBuilder; namespace RentADeveloper.DbConnectionPlus; @@ -105,9 +105,8 @@ public static DataRow QueryFirst( return DataRowMaterializer.Materialize(reader); } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -181,25 +180,25 @@ public static async Task QueryFirstAsync( var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - var (command, commandDisposer) = await DbCommandBuilder.BuildDbCommandAsync( - statement, - databaseAdapter, - connection, - transaction, - commandTimeout, - commandType, - cancellationToken - ).ConfigureAwait(false); + var (command, commandDisposer) = await DbCommandBuilder + .BuildDbCommandAsync( + statement, + databaseAdapter, + connection, + transaction, + commandTimeout, + commandType, + cancellationToken + ) + .ConfigureAwait(false); using (commandDisposer) { try { OnBeforeExecutingCommand(command, statement.TemporaryTables); - var reader = await command.ExecuteReaderAsync( - CommandBehavior.SingleResult | CommandBehavior.SingleRow, - cancellationToken - ) + var reader = await command + .ExecuteReaderAsync(CommandBehavior.SingleResult | CommandBehavior.SingleRow, cancellationToken) .ConfigureAwait(false); await using (reader) @@ -212,9 +211,8 @@ public static async Task QueryFirstAsync( return DataRowMaterializer.Materialize(reader); } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.QueryFirstOfT.cs b/src/DbConnectionPlus/DbConnectionExtensions.QueryFirstOfT.cs index 311887b..4a68e69 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.QueryFirstOfT.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.QueryFirstOfT.cs @@ -109,33 +109,33 @@ public static partial class DbConnectionExtensions /// In this case the first row in the result set will be materialized into an instance of the entity /// type, with the constructor arguments or properties of the entity being populated from the /// corresponding columns of the row. - /// + /// /// All columns returned by the SQL statement must have a name. - /// + /// /// The type must either: - /// + /// /// 1. Have a constructor whose parameters match the columns of the result set returned by the /// statement. /// The names of the parameters must match the names of the columns (case-insensitive). /// The types of the parameters must be compatible with the data types of the columns. /// The compatibility is determined using . /// The parameters can be in any order. - /// + /// /// Or - /// + /// /// 2. Have a parameterless constructor and properties (with public setters) that match the columns of /// the result set returned by the statement. - /// + /// /// Per default, the names of the properties must match the names of the columns (case-insensitive). /// This can be configured via or . - /// + /// /// The types of the properties must be compatible with the data types of the columns. /// The compatibility is determined using . - /// + /// /// Columns without a matching property will be ignored. - /// + /// /// If neither condition is satisfied, an will be thrown. - /// + /// /// If a constructor parameter or a property cannot be set to the value of the corresponding column /// due to a type mismatch, an will be thrown. /// @@ -146,14 +146,14 @@ public static partial class DbConnectionExtensions /// In this case the first row in the result set will be materialized into an instance of the value /// tuple type, with the fields of the value tuple being populated from the corresponding columns of the /// row. - /// + /// /// All columns returned by the SQL statement must have a name. /// The SQL statement must return the same number of columns as the value tuple has fields. /// The SQL statement must return the columns in the same order as the fields in the value tuple. - /// + /// /// The data types of the columns must be compatible with the field types of the value tuple. /// The compatibility is determined using . - /// + /// /// If those conditions are not met, an is thrown. /// /// @@ -164,7 +164,7 @@ public static partial class DbConnectionExtensions /// /// ($"SELECT * FROM [Order] WHERE Id = {Parameter(orderId)}"); /// ]]> /// /// - public static T QueryFirst< - [DynamicallyAccessedMembers(EntityHelper.QueryResultMemberTypes)] T - >( + public static T QueryFirst<[DynamicallyAccessedMembers(EntityHelper.QueryResultMemberTypes)] T>( this DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, @@ -211,8 +209,8 @@ public static T QueryFirst< using (reader) { - var isTBuiltInTypeOrEnumType = typeof(T).IsBuiltInTypeOrNullableBuiltInType() || - typeof(T).IsEnumOrNullableEnumType(); + var isTBuiltInTypeOrEnumType = + typeof(T).IsBuiltInTypeOrNullableBuiltInType() || typeof(T).IsEnumOrNullableEnumType(); var isTValueTupleType = typeof(T).IsValueTupleType(); var isTEntityType = !isTBuiltInTypeOrEnumType && !isTValueTupleType; @@ -253,9 +251,8 @@ public static T QueryFirst< return entityMaterializer(reader); } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -358,33 +355,33 @@ public static T QueryFirst< /// In this case the first row in the result set will be materialized into an instance of the entity /// type, with the constructor arguments or properties of the entity being populated from the /// corresponding columns of the row. - /// + /// /// All columns returned by the SQL statement must have a name. - /// + /// /// The type must either: - /// + /// /// 1. Have a constructor whose parameters match the columns of the result set returned by the /// statement. /// The names of the parameters must match the names of the columns (case-insensitive). /// The types of the parameters must be compatible with the data types of the columns. /// The compatibility is determined using . /// The parameters can be in any order. - /// + /// /// Or - /// + /// /// 2. Have a parameterless constructor and properties (with public setters) that match the columns of /// the result set returned by the statement. - /// + /// /// Per default, the names of the properties must match the names of the columns (case-insensitive). /// This can be configured via or . - /// + /// /// The types of the properties must be compatible with the data types of the columns. /// The compatibility is determined using . - /// + /// /// Columns without a matching property will be ignored. - /// + /// /// If neither condition is satisfied, an will be thrown. - /// + /// /// If a constructor parameter or a property cannot be set to the value of the corresponding column /// due to a type mismatch, an will be thrown. /// @@ -395,14 +392,14 @@ public static T QueryFirst< /// In this case the first row in the result set will be materialized into an instance of the value /// tuple type, with the fields of the value tuple being populated from the corresponding columns of the /// row. - /// + /// /// All columns returned by the SQL statement must have a name. /// The SQL statement must return the same number of columns as the value tuple has fields. /// The SQL statement must return the columns in the same order as the fields in the value tuple. - /// + /// /// The data types of the columns must be compatible with the field types of the value tuple. /// The compatibility is determined using . - /// + /// /// If those conditions are not met, an is thrown. /// /// @@ -413,7 +410,7 @@ public static T QueryFirst< /// /// ($"SELECT * FROM [Order] WHERE Id = {Parameter(orderId)}"); /// ]]> /// /// - public static async Task QueryFirstAsync< - [DynamicallyAccessedMembers(EntityHelper.QueryResultMemberTypes)] T - >( + public static async Task QueryFirstAsync<[DynamicallyAccessedMembers(EntityHelper.QueryResultMemberTypes)] T>( this DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, @@ -441,31 +436,31 @@ public static async Task QueryFirstAsync< var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - var (command, commandDisposer) = await DbCommandBuilder.BuildDbCommandAsync( - statement, - databaseAdapter, - connection, - transaction, - commandTimeout, - commandType, - cancellationToken - ).ConfigureAwait(false); + var (command, commandDisposer) = await DbCommandBuilder + .BuildDbCommandAsync( + statement, + databaseAdapter, + connection, + transaction, + commandTimeout, + commandType, + cancellationToken + ) + .ConfigureAwait(false); using (commandDisposer) { try { OnBeforeExecutingCommand(command, statement.TemporaryTables); - var reader = await command.ExecuteReaderAsync( - CommandBehavior.SingleResult | CommandBehavior.SingleRow, - cancellationToken - ) + var reader = await command + .ExecuteReaderAsync(CommandBehavior.SingleResult | CommandBehavior.SingleRow, cancellationToken) .ConfigureAwait(false); await using (reader) { - var isTBuiltInTypeOrEnumType = typeof(T).IsBuiltInTypeOrNullableBuiltInType() || - typeof(T).IsEnumOrNullableEnumType(); + var isTBuiltInTypeOrEnumType = + typeof(T).IsBuiltInTypeOrNullableBuiltInType() || typeof(T).IsEnumOrNullableEnumType(); var isTValueTupleType = typeof(T).IsValueTupleType(); var isTEntityType = !isTBuiltInTypeOrEnumType && !isTValueTupleType; @@ -506,9 +501,8 @@ public static async Task QueryFirstAsync< return entityMaterializer(reader); } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.QueryFirstOrDefault.cs b/src/DbConnectionPlus/DbConnectionExtensions.QueryFirstOrDefault.cs index f043c50..61f761d 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.QueryFirstOrDefault.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.QueryFirstOrDefault.cs @@ -3,8 +3,8 @@ using RentADeveloper.DbConnectionPlus.Materializers; using RentADeveloper.DbConnectionPlus.SqlStatements; -using DbCommandBuilder = RentADeveloper.DbConnectionPlus.DbCommands.DbCommandBuilder; using DataRow = RentADeveloper.DbConnectionPlus.Dynamic.DataRow; +using DbCommandBuilder = RentADeveloper.DbConnectionPlus.DbCommands.DbCommandBuilder; namespace RentADeveloper.DbConnectionPlus; @@ -111,9 +111,8 @@ public static partial class DbConnectionExtensions return DataRowMaterializer.Materialize(reader); } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -193,25 +192,25 @@ public static partial class DbConnectionExtensions var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - var (command, commandDisposer) = await DbCommandBuilder.BuildDbCommandAsync( - statement, - databaseAdapter, - connection, - transaction, - commandTimeout, - commandType, - cancellationToken - ).ConfigureAwait(false); + var (command, commandDisposer) = await DbCommandBuilder + .BuildDbCommandAsync( + statement, + databaseAdapter, + connection, + transaction, + commandTimeout, + commandType, + cancellationToken + ) + .ConfigureAwait(false); using (commandDisposer) { try { OnBeforeExecutingCommand(command, statement.TemporaryTables); - var reader = await command.ExecuteReaderAsync( - CommandBehavior.SingleResult | CommandBehavior.SingleRow, - cancellationToken - ) + var reader = await command + .ExecuteReaderAsync(CommandBehavior.SingleResult | CommandBehavior.SingleRow, cancellationToken) .ConfigureAwait(false); await using (reader) @@ -224,9 +223,8 @@ public static partial class DbConnectionExtensions return DataRowMaterializer.Materialize(reader); } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.QueryFirstOrDefaultOfT.cs b/src/DbConnectionPlus/DbConnectionExtensions.QueryFirstOrDefaultOfT.cs index 3f11f57..46d94d2 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.QueryFirstOrDefaultOfT.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.QueryFirstOrDefaultOfT.cs @@ -109,33 +109,33 @@ public static partial class DbConnectionExtensions /// In this case the first row in the result set will be materialized into an instance of the entity /// type, with the constructor arguments or properties of the entity being populated from the /// corresponding columns of the row. - /// + /// /// All columns returned by the SQL statement must have a name. - /// + /// /// The type must either: - /// + /// /// 1. Have a constructor whose parameters match the columns of the result set returned by the /// statement. /// The names of the parameters must match the names of the columns (case-insensitive). /// The types of the parameters must be compatible with the data types of the columns. /// The compatibility is determined using . /// The parameters can be in any order. - /// + /// /// Or - /// + /// /// 2. Have a parameterless constructor and properties (with public setters) that match the columns of /// the result set returned by the statement. - /// + /// /// Per default, the names of the properties must match the names of the columns (case-insensitive). /// This can be configured via or . - /// + /// /// The types of the properties must be compatible with the data types of the columns. /// The compatibility is determined using . - /// + /// /// Columns without a matching property will be ignored. - /// + /// /// If neither condition is satisfied, an will be thrown. - /// + /// /// If a constructor parameter or a property cannot be set to the value of the corresponding column /// due to a type mismatch, an will be thrown. /// @@ -146,14 +146,14 @@ public static partial class DbConnectionExtensions /// In this case the first row in the result set will be materialized into an instance of the value /// tuple type, with the fields of the value tuple being populated from the corresponding columns of the /// row. - /// + /// /// All columns returned by the SQL statement must have a name. /// The SQL statement must return the same number of columns as the value tuple has fields. /// The SQL statement must return the columns in the same order as the fields in the value tuple. - /// + /// /// The data types of the columns must be compatible with the field types of the value tuple. /// The compatibility is determined using . - /// + /// /// If those conditions are not met, an is thrown. /// /// @@ -164,7 +164,7 @@ public static partial class DbConnectionExtensions /// /// ($"SELECT * FROM [Order] WHERE Id = {Parameter(orderId)}"); /// ]]> /// /// - public static T? QueryFirstOrDefault< - [DynamicallyAccessedMembers(EntityHelper.QueryResultMemberTypes)] T - >( + public static T? QueryFirstOrDefault<[DynamicallyAccessedMembers(EntityHelper.QueryResultMemberTypes)] T>( this DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, @@ -211,8 +209,8 @@ public static T? QueryFirstOrDefault< using (reader) { - var isTBuiltInTypeOrEnumType = typeof(T).IsBuiltInTypeOrNullableBuiltInType() || - typeof(T).IsEnumOrNullableEnumType(); + var isTBuiltInTypeOrEnumType = + typeof(T).IsBuiltInTypeOrNullableBuiltInType() || typeof(T).IsEnumOrNullableEnumType(); var isTValueTupleType = typeof(T).IsValueTupleType(); var isTEntityType = !isTBuiltInTypeOrEnumType && !isTValueTupleType; @@ -253,9 +251,8 @@ public static T? QueryFirstOrDefault< return entityMaterializer(reader); } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -360,33 +357,33 @@ public static T? QueryFirstOrDefault< /// In this case the first row in the result set will be materialized into an instance of the entity /// type, with the constructor arguments or properties of the entity being populated from the /// corresponding columns of the row. - /// + /// /// All columns returned by the SQL statement must have a name. - /// + /// /// The type must either: - /// + /// /// 1. Have a constructor whose parameters match the columns of the result set returned by the /// statement. /// The names of the parameters must match the names of the columns (case-insensitive). /// The types of the parameters must be compatible with the data types of the columns. /// The compatibility is determined using . /// The parameters can be in any order. - /// + /// /// Or - /// + /// /// 2. Have a parameterless constructor and properties (with public setters) that match the columns of /// the result set returned by the statement. - /// + /// /// Per default, the names of the properties must match the names of the columns (case-insensitive). /// This can be configured via or . - /// + /// /// The types of the properties must be compatible with the data types of the columns. /// The compatibility is determined using . - /// + /// /// Columns without a matching property will be ignored. - /// + /// /// If neither condition is satisfied, an will be thrown. - /// + /// /// If a constructor parameter or a property cannot be set to the value of the corresponding column /// due to a type mismatch, an will be thrown. /// @@ -397,14 +394,14 @@ public static T? QueryFirstOrDefault< /// In this case the first row in the result set will be materialized into an instance of the value /// tuple type, with the fields of the value tuple being populated from the corresponding columns of the /// row. - /// + /// /// All columns returned by the SQL statement must have a name. /// The SQL statement must return the same number of columns as the value tuple has fields. /// The SQL statement must return the columns in the same order as the fields in the value tuple. - /// + /// /// The data types of the columns must be compatible with the field types of the value tuple. /// The compatibility is determined using . - /// + /// /// If those conditions are not met, an is thrown. /// /// @@ -415,7 +412,7 @@ public static T? QueryFirstOrDefault< /// /// ( /// $"SELECT * FROM [Order] WHERE Id = {Parameter(orderId)}" /// ); @@ -445,31 +442,31 @@ public static async Task QueryFirstOrDefaultAsync< var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - var (command, commandDisposer) = await DbCommandBuilder.BuildDbCommandAsync( - statement, - databaseAdapter, - connection, - transaction, - commandTimeout, - commandType, - cancellationToken - ).ConfigureAwait(false); + var (command, commandDisposer) = await DbCommandBuilder + .BuildDbCommandAsync( + statement, + databaseAdapter, + connection, + transaction, + commandTimeout, + commandType, + cancellationToken + ) + .ConfigureAwait(false); using (commandDisposer) { try { OnBeforeExecutingCommand(command, statement.TemporaryTables); - var reader = await command.ExecuteReaderAsync( - CommandBehavior.SingleResult | CommandBehavior.SingleRow, - cancellationToken - ) + var reader = await command + .ExecuteReaderAsync(CommandBehavior.SingleResult | CommandBehavior.SingleRow, cancellationToken) .ConfigureAwait(false); await using (reader) { - var isTBuiltInTypeOrEnumType = typeof(T).IsBuiltInTypeOrNullableBuiltInType() || - typeof(T).IsEnumOrNullableEnumType(); + var isTBuiltInTypeOrEnumType = + typeof(T).IsBuiltInTypeOrNullableBuiltInType() || typeof(T).IsEnumOrNullableEnumType(); var isTValueTupleType = typeof(T).IsValueTupleType(); var isTEntityType = !isTBuiltInTypeOrEnumType && !isTValueTupleType; @@ -510,9 +507,8 @@ public static async Task QueryFirstOrDefaultAsync< return entityMaterializer(reader); } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.QueryOfT.cs b/src/DbConnectionPlus/DbConnectionExtensions.QueryOfT.cs index 259046a..1aa1ee0 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.QueryOfT.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.QueryOfT.cs @@ -106,33 +106,33 @@ public static partial class DbConnectionExtensions /// In this case each row in the result set will be materialized into an instance of the entity type, /// with the constructor arguments or properties of the entity being populated from the corresponding /// columns of the row. - /// + /// /// All columns returned by the SQL statement must have a name. - /// + /// /// The type must either: - /// + /// /// 1. Have a constructor whose parameters match the columns of the result set returned by the /// statement. /// The names of the parameters must match the names of the columns (case-insensitive). /// The types of the parameters must be compatible with the data types of the columns. /// The compatibility is determined using . /// The parameters can be in any order. - /// + /// /// Or - /// + /// /// 2. Have a parameterless constructor and properties (with public setters) that match the columns of /// the result set returned by the statement. - /// + /// /// Per default, the names of the properties must match the names of the columns (case-insensitive). /// This can be configured via or . - /// + /// /// The types of the properties must be compatible with the data types of the columns. /// The compatibility is determined using . - /// + /// /// Columns without a matching property will be ignored. - /// + /// /// If neither condition is satisfied, an will be thrown. - /// + /// /// If a constructor parameter or a property cannot be set to the value of the corresponding column /// due to a type mismatch, an will be thrown. /// @@ -143,14 +143,14 @@ public static partial class DbConnectionExtensions /// In this case each row in the result set will be materialized into an instance of the value tuple /// type, with the fields of the value tuple being populated from the corresponding columns of the /// row. - /// + /// /// All columns returned by the SQL statement must have a name. /// The SQL statement must return the same number of columns as the value tuple has fields. /// The SQL statement must return the columns in the same order as the fields in the value tuple. - /// + /// /// The data types of the columns must be compatible with the field types of the value tuple. /// The compatibility is determined using . - /// + /// /// If those conditions are not met, an is thrown. /// /// @@ -161,18 +161,16 @@ public static partial class DbConnectionExtensions /// /// ( /// $"SELECT * FROM Product WHERE UnitsInStock < {Parameter(lowStockThreshold)}" /// ); /// ]]> /// /// - public static IEnumerable Query< - [DynamicallyAccessedMembers(EntityHelper.QueryResultMemberTypes)] T - >( + public static IEnumerable Query<[DynamicallyAccessedMembers(EntityHelper.QueryResultMemberTypes)] T>( this DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, @@ -204,9 +202,8 @@ public static IEnumerable Query< OnBeforeExecutingCommand(command, statement.TemporaryTables); reader = command.ExecuteReader(); } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { reader?.Dispose(); @@ -215,8 +212,8 @@ public static IEnumerable Query< using (reader) { - var isTBuiltInTypeOrEnumType = typeof(T).IsBuiltInTypeOrNullableBuiltInType() || - typeof(T).IsEnumOrNullableEnumType(); + var isTBuiltInTypeOrEnumType = + typeof(T).IsBuiltInTypeOrNullableBuiltInType() || typeof(T).IsEnumOrNullableEnumType(); var isTValueTupleType = typeof(T).IsValueTupleType(); var isTEntityType = !isTBuiltInTypeOrEnumType && !isTValueTupleType; @@ -245,9 +242,8 @@ public static IEnumerable Query< yield break; } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -370,33 +366,33 @@ public static IEnumerable Query< /// In this case each row in the result set will be materialized into an instance of the entity type, /// with the constructor arguments or properties of the entity being populated from the corresponding /// columns of the row. - /// + /// /// All columns returned by the SQL statement must have a name. - /// + /// /// The type must either: - /// + /// /// 1. Have a constructor whose parameters match the columns of the result set returned by the /// statement. /// The names of the parameters must match the names of the columns (case-insensitive). /// The types of the parameters must be compatible with the data types of the columns. /// The compatibility is determined using . /// The parameters can be in any order. - /// + /// /// Or - /// + /// /// 2. Have a parameterless constructor and properties (with public setters) that match the columns of /// the result set returned by the statement. - /// + /// /// Per default, the names of the properties must match the names of the columns (case-insensitive). /// This can be configured via or . - /// + /// /// The types of the properties must be compatible with the data types of the columns. /// The compatibility is determined using . - /// + /// /// Columns without a matching property will be ignored. - /// + /// /// If neither condition is satisfied, an will be thrown. - /// + /// /// If a constructor parameter or a property cannot be set to the value of the corresponding column /// due to a type mismatch, an will be thrown. /// @@ -407,14 +403,14 @@ public static IEnumerable Query< /// In this case each row in the result set will be materialized into an instance of the value tuple /// type, with the fields of the value tuple being populated from the corresponding columns of the /// row. - /// + /// /// All columns returned by the SQL statement must have a name. /// The SQL statement must return the same number of columns as the value tuple has fields. /// The SQL statement must return the columns in the same order as the fields in the value tuple. - /// + /// /// The data types of the columns must be compatible with the field types of the value tuple. /// The compatibility is determined using . - /// + /// /// If those conditions are not met, an is thrown. /// /// @@ -425,9 +421,9 @@ public static IEnumerable Query< /// /// ( /// $"SELECT * FROM Product WHERE UnitsInStock < {Parameter(lowStockThreshold)}" /// ); @@ -449,15 +445,17 @@ public static async IAsyncEnumerable QueryAsync< var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - var (command, commandDisposer) = await DbCommandBuilder.BuildDbCommandAsync( - statement, - databaseAdapter, - connection, - transaction, - commandTimeout, - commandType, - cancellationToken - ).ConfigureAwait(false); + var (command, commandDisposer) = await DbCommandBuilder + .BuildDbCommandAsync( + statement, + databaseAdapter, + connection, + transaction, + commandTimeout, + commandType, + cancellationToken + ) + .ConfigureAwait(false); using (commandDisposer) { @@ -468,9 +466,8 @@ public static async IAsyncEnumerable QueryAsync< OnBeforeExecutingCommand(command, statement.TemporaryTables); reader = await command.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false); } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { if (reader is not null) { @@ -482,8 +479,8 @@ public static async IAsyncEnumerable QueryAsync< await using (reader) { - var isTBuiltInTypeOrEnumType = typeof(T).IsBuiltInTypeOrNullableBuiltInType() || - typeof(T).IsEnumOrNullableEnumType(); + var isTBuiltInTypeOrEnumType = + typeof(T).IsBuiltInTypeOrNullableBuiltInType() || typeof(T).IsEnumOrNullableEnumType(); var isTValueTupleType = typeof(T).IsValueTupleType(); var isTEntityType = !isTBuiltInTypeOrEnumType && !isTValueTupleType; @@ -512,9 +509,8 @@ public static async IAsyncEnumerable QueryAsync< yield break; } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -564,16 +560,16 @@ private static TTarget ConvertValueForQuery(object? value) catch (Exception exception) when (value is DBNull) { throw new InvalidCastException( - "The first column returned by the SQL statement contains a NULL value, which could not be converted " + - $"to the type {typeof(TTarget)}. See inner exception for details.", + "The first column returned by the SQL statement contains a NULL value, which could not be converted " + + $"to the type {typeof(TTarget)}. See inner exception for details.", exception ); } catch (Exception exception) when (value is not null) { throw new InvalidCastException( - $"The first column returned by the SQL statement contains the value {value.ToDebugString()}, which " + - $"could not be converted to the type {typeof(TTarget)}. See inner exception for details.", + $"The first column returned by the SQL statement contains the value {value.ToDebugString()}, which " + + $"could not be converted to the type {typeof(TTarget)}. See inner exception for details.", exception ); } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.QuerySingle.cs b/src/DbConnectionPlus/DbConnectionExtensions.QuerySingle.cs index 5dd7e0e..6dc13b0 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.QuerySingle.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.QuerySingle.cs @@ -3,8 +3,8 @@ using RentADeveloper.DbConnectionPlus.Materializers; using RentADeveloper.DbConnectionPlus.SqlStatements; -using DbCommandBuilder = RentADeveloper.DbConnectionPlus.DbCommands.DbCommandBuilder; using DataRow = RentADeveloper.DbConnectionPlus.Dynamic.DataRow; +using DbCommandBuilder = RentADeveloper.DbConnectionPlus.DbCommands.DbCommandBuilder; namespace RentADeveloper.DbConnectionPlus; @@ -125,9 +125,8 @@ public static DataRow QuerySingle( return dataRow; } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -214,25 +213,25 @@ public static async Task QuerySingleAsync( var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - var (command, commandDisposer) = await DbCommandBuilder.BuildDbCommandAsync( - statement, - databaseAdapter, - connection, - transaction, - commandTimeout, - commandType, - cancellationToken - ).ConfigureAwait(false); + var (command, commandDisposer) = await DbCommandBuilder + .BuildDbCommandAsync( + statement, + databaseAdapter, + connection, + transaction, + commandTimeout, + commandType, + cancellationToken + ) + .ConfigureAwait(false); using (commandDisposer) { try { OnBeforeExecutingCommand(command, statement.TemporaryTables); - var reader = await command.ExecuteReaderAsync( - CommandBehavior.SingleResult, - cancellationToken - ) + var reader = await command + .ExecuteReaderAsync(CommandBehavior.SingleResult, cancellationToken) .ConfigureAwait(false); await using (reader) @@ -252,9 +251,8 @@ public static async Task QuerySingleAsync( return dataRow; } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.QuerySingleOfT.cs b/src/DbConnectionPlus/DbConnectionExtensions.QuerySingleOfT.cs index eba001c..6dde24b 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.QuerySingleOfT.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.QuerySingleOfT.cs @@ -122,33 +122,33 @@ public static partial class DbConnectionExtensions /// In this case the single row in the result set will be materialized into an instance of the entity /// type, with the constructor arguments or properties of the entity being populated from the /// corresponding columns of the row. - /// + /// /// All columns returned by the SQL statement must have a name. - /// + /// /// The type must either: - /// + /// /// 1. Have a constructor whose parameters match the columns of the result set returned by the /// statement. /// The names of the parameters must match the names of the columns (case-insensitive). /// The types of the parameters must be compatible with the data types of the columns. /// The compatibility is determined using . /// The parameters can be in any order. - /// + /// /// Or - /// + /// /// 2. Have a parameterless constructor and properties (with public setters) that match the columns of /// the result set returned by the statement. - /// + /// /// Per default, the names of the properties must match the names of the columns (case-insensitive). /// This can be configured via or . - /// + /// /// The types of the properties must be compatible with the data types of the columns. /// The compatibility is determined using . - /// + /// /// Columns without a matching property will be ignored. - /// + /// /// If neither condition is satisfied, an will be thrown. - /// + /// /// If a constructor parameter or a property cannot be set to the value of the corresponding column /// due to a type mismatch, an will be thrown. /// @@ -159,14 +159,14 @@ public static partial class DbConnectionExtensions /// In this case the single row in the result set will be materialized into an instance of the value /// tuple type, with the fields of the value tuple being populated from the corresponding columns of the /// row. - /// + /// /// All columns returned by the SQL statement must have a name. /// The SQL statement must return the same number of columns as the value tuple has fields. /// The SQL statement must return the columns in the same order as the fields in the value tuple. - /// + /// /// The data types of the columns must be compatible with the field types of the value tuple. /// The compatibility is determined using . - /// + /// /// If those conditions are not met, an is thrown. /// /// @@ -177,7 +177,7 @@ public static partial class DbConnectionExtensions /// /// ($"SELECT * FROM [Order] WHERE Id = {Parameter(orderId)}"); /// ]]> /// /// - public static T QuerySingle< - [DynamicallyAccessedMembers(EntityHelper.QueryResultMemberTypes)] T - >( + public static T QuerySingle<[DynamicallyAccessedMembers(EntityHelper.QueryResultMemberTypes)] T>( this DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, @@ -224,8 +222,8 @@ public static T QuerySingle< using (reader) { - var isTBuiltInTypeOrEnumType = typeof(T).IsBuiltInTypeOrNullableBuiltInType() || - typeof(T).IsEnumOrNullableEnumType(); + var isTBuiltInTypeOrEnumType = + typeof(T).IsBuiltInTypeOrNullableBuiltInType() || typeof(T).IsEnumOrNullableEnumType(); var isTValueTupleType = typeof(T).IsValueTupleType(); var isTEntityType = !isTBuiltInTypeOrEnumType && !isTValueTupleType; @@ -276,9 +274,8 @@ public static T QuerySingle< return result; } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -394,33 +391,33 @@ public static T QuerySingle< /// In this case the single row in the result set will be materialized into an instance of the entity /// type, with the constructor arguments or properties of the entity being populated from the /// corresponding columns of the row. - /// + /// /// All columns returned by the SQL statement must have a name. - /// + /// /// The type must either: - /// + /// /// 1. Have a constructor whose parameters match the columns of the result set returned by the /// statement. /// The names of the parameters must match the names of the columns (case-insensitive). /// The types of the parameters must be compatible with the data types of the columns. /// The compatibility is determined using . /// The parameters can be in any order. - /// + /// /// Or - /// + /// /// 2. Have a parameterless constructor and properties (with public setters) that match the columns of /// the result set returned by the statement. - /// + /// /// Per default, the names of the properties must match the names of the columns (case-insensitive). /// This can be configured via or . - /// + /// /// The types of the properties must be compatible with the data types of the columns. /// The compatibility is determined using . - /// + /// /// Columns without a matching property will be ignored. - /// + /// /// If neither condition is satisfied, an will be thrown. - /// + /// /// If a constructor parameter or a property cannot be set to the value of the corresponding column /// due to a type mismatch, an will be thrown. /// @@ -431,14 +428,14 @@ public static T QuerySingle< /// In this case the single row in the result set will be materialized into an instance of the value /// tuple type, with the fields of the value tuple being populated from the corresponding columns of the /// row. - /// + /// /// All columns returned by the SQL statement must have a name. /// The SQL statement must return the same number of columns as the value tuple has fields. /// The SQL statement must return the columns in the same order as the fields in the value tuple. - /// + /// /// The data types of the columns must be compatible with the field types of the value tuple. /// The compatibility is determined using . - /// + /// /// If those conditions are not met, an is thrown. /// /// @@ -449,7 +446,7 @@ public static T QuerySingle< /// /// ($"SELECT * FROM [Order] WHERE Id = {Parameter(orderId)}"); /// ]]> /// /// - public static async Task QuerySingleAsync< - [DynamicallyAccessedMembers(EntityHelper.QueryResultMemberTypes)] T - >( + public static async Task QuerySingleAsync<[DynamicallyAccessedMembers(EntityHelper.QueryResultMemberTypes)] T>( this DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, @@ -477,28 +472,31 @@ public static async Task QuerySingleAsync< var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - var (command, commandDisposer) = await DbCommandBuilder.BuildDbCommandAsync( - statement, - databaseAdapter, - connection, - transaction, - commandTimeout, - commandType, - cancellationToken - ).ConfigureAwait(false); + var (command, commandDisposer) = await DbCommandBuilder + .BuildDbCommandAsync( + statement, + databaseAdapter, + connection, + transaction, + commandTimeout, + commandType, + cancellationToken + ) + .ConfigureAwait(false); using (commandDisposer) { try { OnBeforeExecutingCommand(command, statement.TemporaryTables); - var reader = await command.ExecuteReaderAsync(CommandBehavior.SingleResult, cancellationToken) + var reader = await command + .ExecuteReaderAsync(CommandBehavior.SingleResult, cancellationToken) .ConfigureAwait(false); await using (reader) { - var isTBuiltInTypeOrEnumType = typeof(T).IsBuiltInTypeOrNullableBuiltInType() || - typeof(T).IsEnumOrNullableEnumType(); + var isTBuiltInTypeOrEnumType = + typeof(T).IsBuiltInTypeOrNullableBuiltInType() || typeof(T).IsEnumOrNullableEnumType(); var isTValueTupleType = typeof(T).IsValueTupleType(); var isTEntityType = !isTBuiltInTypeOrEnumType && !isTValueTupleType; @@ -549,9 +547,8 @@ public static async Task QuerySingleAsync< return result; } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.QuerySingleOrDefault.cs b/src/DbConnectionPlus/DbConnectionExtensions.QuerySingleOrDefault.cs index 41c8cd7..61ce0e4 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.QuerySingleOrDefault.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.QuerySingleOrDefault.cs @@ -3,8 +3,8 @@ using RentADeveloper.DbConnectionPlus.Materializers; using RentADeveloper.DbConnectionPlus.SqlStatements; -using DbCommandBuilder = RentADeveloper.DbConnectionPlus.DbCommands.DbCommandBuilder; using DataRow = RentADeveloper.DbConnectionPlus.Dynamic.DataRow; +using DbCommandBuilder = RentADeveloper.DbConnectionPlus.DbCommands.DbCommandBuilder; namespace RentADeveloper.DbConnectionPlus; @@ -119,9 +119,8 @@ public static partial class DbConnectionExtensions return dataRow; } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -202,25 +201,25 @@ public static partial class DbConnectionExtensions var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - var (command, commandDisposer) = await DbCommandBuilder.BuildDbCommandAsync( - statement, - databaseAdapter, - connection, - transaction, - commandTimeout, - commandType, - cancellationToken - ).ConfigureAwait(false); + var (command, commandDisposer) = await DbCommandBuilder + .BuildDbCommandAsync( + statement, + databaseAdapter, + connection, + transaction, + commandTimeout, + commandType, + cancellationToken + ) + .ConfigureAwait(false); using (commandDisposer) { try { OnBeforeExecutingCommand(command, statement.TemporaryTables); - var reader = await command.ExecuteReaderAsync( - CommandBehavior.SingleResult, - cancellationToken - ) + var reader = await command + .ExecuteReaderAsync(CommandBehavior.SingleResult, cancellationToken) .ConfigureAwait(false); await using (reader) @@ -240,9 +239,8 @@ public static partial class DbConnectionExtensions return dataRow; } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.QuerySingleOrDefaultOfT.cs b/src/DbConnectionPlus/DbConnectionExtensions.QuerySingleOrDefaultOfT.cs index c28c5df..8644d2b 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.QuerySingleOrDefaultOfT.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.QuerySingleOrDefaultOfT.cs @@ -110,33 +110,33 @@ public static partial class DbConnectionExtensions /// In this case the single row in the result set will be materialized into an instance of the entity /// type, with the constructor arguments or properties of the entity being populated from the /// corresponding columns of the row. - /// + /// /// All columns returned by the SQL statement must have a name. - /// + /// /// The type must either: - /// + /// /// 1. Have a constructor whose parameters match the columns of the result set returned by the /// statement. /// The names of the parameters must match the names of the columns (case-insensitive). /// The types of the parameters must be compatible with the data types of the columns. /// The compatibility is determined using . /// The parameters can be in any order. - /// + /// /// Or - /// + /// /// 2. Have a parameterless constructor and properties (with public setters) that match the columns of /// the result set returned by the statement. - /// + /// /// Per default, the names of the properties must match the names of the columns (case-insensitive). /// This can be configured via or . - /// + /// /// The types of the properties must be compatible with the data types of the columns. /// The compatibility is determined using . - /// + /// /// Columns without a matching property will be ignored. - /// + /// /// If neither condition is satisfied, an will be thrown. - /// + /// /// If a constructor parameter or a property cannot be set to the value of the corresponding column /// due to a type mismatch, an will be thrown. /// @@ -147,14 +147,14 @@ public static partial class DbConnectionExtensions /// In this case the single row in the result set will be materialized into an instance of the value /// tuple type, with the fields of the value tuple being populated from the corresponding columns of the /// row. - /// + /// /// All columns returned by the SQL statement must have a name. /// The SQL statement must return the same number of columns as the value tuple has fields. /// The SQL statement must return the columns in the same order as the fields in the value tuple. - /// + /// /// The data types of the columns must be compatible with the field types of the value tuple. /// The compatibility is determined using . - /// + /// /// If those conditions are not met, an is thrown. /// /// @@ -165,7 +165,7 @@ public static partial class DbConnectionExtensions /// /// ($"SELECT * FROM [Order] WHERE Id = {Parameter(orderId)}"); /// ]]> /// /// - public static T? QuerySingleOrDefault< - [DynamicallyAccessedMembers(EntityHelper.QueryResultMemberTypes)] T - >( + public static T? QuerySingleOrDefault<[DynamicallyAccessedMembers(EntityHelper.QueryResultMemberTypes)] T>( this DbConnection connection, InterpolatedSqlStatement statement, DbTransaction? transaction = null, @@ -212,8 +210,8 @@ public static T? QuerySingleOrDefault< using (reader) { - var isTBuiltInTypeOrEnumType = typeof(T).IsBuiltInTypeOrNullableBuiltInType() || - typeof(T).IsEnumOrNullableEnumType(); + var isTBuiltInTypeOrEnumType = + typeof(T).IsBuiltInTypeOrNullableBuiltInType() || typeof(T).IsEnumOrNullableEnumType(); var isTValueTupleType = typeof(T).IsValueTupleType(); var isTEntityType = !isTBuiltInTypeOrEnumType && !isTValueTupleType; @@ -262,9 +260,8 @@ public static T? QuerySingleOrDefault< return result; } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } @@ -369,33 +366,33 @@ public static T? QuerySingleOrDefault< /// In this case the single row in the result set will be materialized into an instance of the entity /// type, with the constructor arguments or properties of the entity being populated from the /// corresponding columns of the row. - /// + /// /// All columns returned by the SQL statement must have a name. - /// + /// /// The type must either: - /// + /// /// 1. Have a constructor whose parameters match the columns of the result set returned by the /// statement. /// The names of the parameters must match the names of the columns (case-insensitive). /// The types of the parameters must be compatible with the data types of the columns. /// The compatibility is determined using . /// The parameters can be in any order. - /// + /// /// Or - /// + /// /// 2. Have a parameterless constructor and properties (with public setters) that match the columns of /// the result set returned by the statement. - /// + /// /// Per default, the names of the properties must match the names of the columns (case-insensitive). /// This can be configured via or . - /// + /// /// The types of the properties must be compatible with the data types of the columns. /// The compatibility is determined using . - /// + /// /// Columns without a matching property will be ignored. - /// + /// /// If neither condition is satisfied, an will be thrown. - /// + /// /// If a constructor parameter or a property cannot be set to the value of the corresponding column /// due to a type mismatch, an will be thrown. /// @@ -406,14 +403,14 @@ public static T? QuerySingleOrDefault< /// In this case the single row in the result set will be materialized into an instance of the value /// tuple type, with the fields of the value tuple being populated from the corresponding columns of the /// row. - /// + /// /// All columns returned by the SQL statement must have a name. /// The SQL statement must return the same number of columns as the value tuple has fields. /// The SQL statement must return the columns in the same order as the fields in the value tuple. - /// + /// /// The data types of the columns must be compatible with the field types of the value tuple. /// The compatibility is determined using . - /// + /// /// If those conditions are not met, an is thrown. /// /// @@ -424,7 +421,7 @@ public static T? QuerySingleOrDefault< /// /// ( /// $"SELECT * FROM [Order] WHERE Id = {Parameter(orderId)}" /// ); @@ -454,28 +451,31 @@ public static async Task QuerySingleOrDefaultAsync< var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - var (command, commandDisposer) = await DbCommandBuilder.BuildDbCommandAsync( - statement, - databaseAdapter, - connection, - transaction, - commandTimeout, - commandType, - cancellationToken - ).ConfigureAwait(false); + var (command, commandDisposer) = await DbCommandBuilder + .BuildDbCommandAsync( + statement, + databaseAdapter, + connection, + transaction, + commandTimeout, + commandType, + cancellationToken + ) + .ConfigureAwait(false); using (commandDisposer) { try { OnBeforeExecutingCommand(command, statement.TemporaryTables); - var reader = await command.ExecuteReaderAsync(CommandBehavior.SingleResult, cancellationToken) + var reader = await command + .ExecuteReaderAsync(CommandBehavior.SingleResult, cancellationToken) .ConfigureAwait(false); await using (reader) { - var isTBuiltInTypeOrEnumType = typeof(T).IsBuiltInTypeOrNullableBuiltInType() || - typeof(T).IsEnumOrNullableEnumType(); + var isTBuiltInTypeOrEnumType = + typeof(T).IsBuiltInTypeOrNullableBuiltInType() || typeof(T).IsEnumOrNullableEnumType(); var isTValueTupleType = typeof(T).IsValueTupleType(); var isTEntityType = !isTBuiltInTypeOrEnumType && !isTValueTupleType; @@ -524,9 +524,8 @@ public static async Task QuerySingleOrDefaultAsync< return result; } } - catch (Exception exception) when ( - databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - ) + catch (Exception exception) + when (databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.TemporaryTable.cs b/src/DbConnectionPlus/DbConnectionExtensions.TemporaryTable.cs index 8ec49ba..76bc56d 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.TemporaryTable.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.TemporaryTable.cs @@ -51,9 +51,9 @@ public static partial class DbConnectionExtensions /// /// a.IsRetired).Select(a => a.Id); - /// + /// /// var retiredSupplierProductsReader = connection.ExecuteReader( /// $""" /// SELECT * @@ -87,16 +87,16 @@ public static partial class DbConnectionExtensions /// /// public static InterpolatedTemporaryTable TemporaryTable< [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] T - >( - IEnumerable values, - [CallerArgumentExpression(nameof(values))] - string? valuesExpression = null - ) + >(IEnumerable values, [CallerArgumentExpression(nameof(values))] string? valuesExpression = null) { ArgumentNullException.ThrowIfNull(values); diff --git a/src/DbConnectionPlus/DbConnectionExtensions.UpdateEntities.cs b/src/DbConnectionPlus/DbConnectionExtensions.UpdateEntities.cs index 176458c..4b4126e 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.UpdateEntities.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.UpdateEntities.cs @@ -79,7 +79,7 @@ public static partial class DbConnectionExtensions /// /// ( /// """ /// SELECT * @@ -95,19 +95,17 @@ public static partial class DbConnectionExtensions /// WHERE LastLoginDate < DATEADD(YEAR, -1, GETUTCDATE()) /// """ /// ); - /// + /// /// foreach (var user in usersWithoutLoginInPastYear) /// { /// user.State = UserState.Inactive; /// } - /// + /// /// connection.UpdateEntities(usersWithoutLoginInPastYear); /// ]]> /// /// - public static int UpdateEntities< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public static int UpdateEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( this DbConnection connection, IEnumerable entities, DbTransaction? transaction = null, @@ -120,12 +118,7 @@ public static int UpdateEntities< var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - return databaseAdapter.EntityManipulator.UpdateEntities( - connection, - entities, - transaction, - cancellationToken - ); + return databaseAdapter.EntityManipulator.UpdateEntities(connection, entities, transaction, cancellationToken); } /// @@ -200,7 +193,7 @@ public static int UpdateEntities< /// /// ( /// """ /// SELECT * @@ -216,19 +209,17 @@ public static int UpdateEntities< /// WHERE LastLoginDate < DATEADD(YEAR, -1, GETUTCDATE()) /// """ /// ); - /// + /// /// await foreach (var user in usersWithoutLoginInPastYear) /// { /// user.State = UserState.Inactive; /// } - /// + /// /// await connection.UpdateEntitiesAsync(usersWithoutLoginInPastYear); /// ]]> /// /// - public static Task UpdateEntitiesAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public static Task UpdateEntitiesAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( this DbConnection connection, IEnumerable entities, DbTransaction? transaction = null, @@ -241,7 +232,11 @@ public static Task UpdateEntitiesAsync< var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - return databaseAdapter.EntityManipulator - .UpdateEntitiesAsync(connection, entities, transaction, cancellationToken); + return databaseAdapter.EntityManipulator.UpdateEntitiesAsync( + connection, + entities, + transaction, + cancellationToken + ); } } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.UpdateEntity.cs b/src/DbConnectionPlus/DbConnectionExtensions.UpdateEntity.cs index 227bcd8..938ee9f 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.UpdateEntity.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.UpdateEntity.cs @@ -79,7 +79,7 @@ public static partial class DbConnectionExtensions /// /// /// /// - public static int UpdateEntity< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public static int UpdateEntity<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( this DbConnection connection, TEntity entity, DbTransaction? transaction = null, @@ -111,12 +109,7 @@ public static int UpdateEntity< var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - return databaseAdapter.EntityManipulator.UpdateEntity( - connection, - entity, - transaction, - cancellationToken - ); + return databaseAdapter.EntityManipulator.UpdateEntity(connection, entity, transaction, cancellationToken); } /// @@ -190,7 +183,7 @@ public static int UpdateEntity< /// /// /// /// - public static Task UpdateEntityAsync< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + public static Task UpdateEntityAsync<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( this DbConnection connection, TEntity entity, DbTransaction? transaction = null, @@ -222,11 +213,6 @@ public static Task UpdateEntityAsync< var databaseAdapter = DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(connection.GetType()); - return databaseAdapter.EntityManipulator.UpdateEntityAsync( - connection, - entity, - transaction, - cancellationToken - ); + return databaseAdapter.EntityManipulator.UpdateEntityAsync(connection, entity, transaction, cancellationToken); } } diff --git a/src/DbConnectionPlus/Dynamic/DataRow.cs b/src/DbConnectionPlus/Dynamic/DataRow.cs index 2f78f93..71f69e4 100644 --- a/src/DbConnectionPlus/Dynamic/DataRow.cs +++ b/src/DbConnectionPlus/Dynamic/DataRow.cs @@ -67,44 +67,34 @@ public object? this[string key] public ICollection Values => this.columns.Values; /// - public void Add(KeyValuePair item) => - this.columns.Add(item); + public void Add(KeyValuePair item) => this.columns.Add(item); /// - public void Add(string key, object? value) => - this.columns.Add(key, value); + public void Add(string key, object? value) => this.columns.Add(key, value); /// - public void Clear() => - this.columns.Clear(); + public void Clear() => this.columns.Clear(); /// - public bool Contains(KeyValuePair item) => - this.columns.Contains(item); + public bool Contains(KeyValuePair item) => this.columns.Contains(item); /// - public bool ContainsKey(string key) => - this.columns.ContainsKey(key); + public bool ContainsKey(string key) => this.columns.ContainsKey(key); /// - public void CopyTo(KeyValuePair[] array, int arrayIndex) => - this.columns.CopyTo(array, arrayIndex); + public void CopyTo(KeyValuePair[] array, int arrayIndex) => this.columns.CopyTo(array, arrayIndex); /// - public IEnumerator> GetEnumerator() => - this.columns.GetEnumerator(); + public IEnumerator> GetEnumerator() => this.columns.GetEnumerator(); /// - public bool Remove(KeyValuePair item) => - this.columns.Remove(item); + public bool Remove(KeyValuePair item) => this.columns.Remove(item); /// - public bool Remove(string key) => - this.columns.Remove(key); + public bool Remove(string key) => this.columns.Remove(key); /// - public bool TryGetValue(string key, out object? value) => - this.columns.TryGetValue(key, out value); + public bool TryGetValue(string key, out object? value) => this.columns.TryGetValue(key, out value); /// /// Returns the that binds member access on this row to its columns. @@ -116,28 +106,24 @@ public bool TryGetValue(string key, out object? value) => /// reference. It is not meant to be called directly. Override it to change how member /// access on a derived row is bound. /// - protected virtual DynamicMetaObject GetMetaObject(Expression parameter) => - new DataRowMetaObject(parameter, this); + protected virtual DynamicMetaObject GetMetaObject(Expression parameter) => new DataRowMetaObject(parameter, this); /// - DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) => - this.GetMetaObject(parameter); + DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) => this.GetMetaObject(parameter); /// - IEnumerator IEnumerable.GetEnumerator() => - this.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); /// /// Reads the value of a column, used as the target of a bound dynamic member read. /// - private static readonly Func readColumn = - static (row, columnName) => row[columnName]; + private static readonly Func readColumn = static (row, columnName) => row[columnName]; /// /// Writes the value of a column and returns it, used as the target of a bound dynamic member write. /// - private static readonly Func writeColumn = - static (row, columnName, value) => row[columnName] = value; + private static readonly Func writeColumn = static (row, columnName, value) => + row[columnName] = value; private readonly IDictionary columns = columns; @@ -169,9 +155,7 @@ private sealed class DataRowMetaObject : DynamicMetaObject /// The expression representing the at the call site. /// The the member access is bound against. internal DataRowMetaObject(Expression expression, DataRow row) - : base(expression, BindingRestrictions.Empty, row) - { - } + : base(expression, BindingRestrictions.Empty, row) { } /// public override DynamicMetaObject BindGetMember(GetMemberBinder binder) @@ -216,15 +200,13 @@ public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicM } /// - public override IEnumerable GetDynamicMemberNames() => - ((DataRow)this.Value!).Keys; + public override IEnumerable GetDynamicMemberNames() => ((DataRow)this.Value!).Keys; /// /// Gets the call-site expression converted to . /// /// The call-site expression converted to . - private UnaryExpression GetRowExpression() => - Expression.Convert(this.Expression, typeof(DataRow)); + private UnaryExpression GetRowExpression() => Expression.Convert(this.Expression, typeof(DataRow)); /// /// Gets the binding restriction that limits the bound call site to the runtime type of the row. diff --git a/src/DbConnectionPlus/Entities/EntityHelper.cs b/src/DbConnectionPlus/Entities/EntityHelper.cs index 7e01109..1cd4a9e 100644 --- a/src/DbConnectionPlus/Entities/EntityHelper.cs +++ b/src/DbConnectionPlus/Entities/EntityHelper.cs @@ -25,9 +25,9 @@ public static class EntityHelper /// silently binds fewer columns. /// internal const DynamicallyAccessedMemberTypes EntityMemberTypes = - DynamicallyAccessedMemberTypes.PublicConstructors | - DynamicallyAccessedMemberTypes.NonPublicConstructors | - DynamicallyAccessedMemberTypes.PublicProperties; + DynamicallyAccessedMemberTypes.PublicConstructors + | DynamicallyAccessedMemberTypes.NonPublicConstructors + | DynamicallyAccessedMemberTypes.PublicProperties; /// /// The members that must survive trimming for a type used as the result type of a query. @@ -38,8 +38,7 @@ public static class EntityHelper /// materializers reflect over — plus the value tuple's public fields. /// internal const DynamicallyAccessedMemberTypes QueryResultMemberTypes = - EntityMemberTypes | - ValueTupleMaterializerFactory.ValueTupleMemberTypes; + EntityMemberTypes | ValueTupleMaterializerFactory.ValueTupleMemberTypes; /// /// The members that must survive trimming for a type whose values are written to a temporary table. @@ -51,8 +50,7 @@ public static class EntityHelper /// , whose contract requires the type's public fields and properties. /// internal const DynamicallyAccessedMemberTypes TemporaryTableValueMemberTypes = - EntityMemberTypes | - DynamicallyAccessedMemberTypes.PublicFields; + EntityMemberTypes | DynamicallyAccessedMemberTypes.PublicFields; /// /// Tries to find a constructor of the type that has parameters compatible to the @@ -62,7 +60,7 @@ public static class EntityHelper /// The type of which to find the constructor. /// /// The expected parameters of the constructor to find. - /// + /// /// The constructor to find must have parameters with the same names (case-insensitive) and compatible types. /// A parameter type is considered compatible if a value of the expected parameter type can be converted to /// the actual parameter type. @@ -85,13 +83,13 @@ public static class EntityHelper /// public static ConstructorInfo? FindCompatibleConstructor( [DynamicallyAccessedMembers(EntityMemberTypes)] Type type, - (string Name, Type Type)[] expectedParameters) + (string Name, Type Type)[] expectedParameters + ) { ArgumentNullException.ThrowIfNull(type); ArgumentNullException.ThrowIfNull(expectedParameters); - var constructors = type - .GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) + var constructors = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .OrderByDescending(c => c.IsPublic) .ThenBy(c => c.IsPrivate) .ThenBy(c => c.GetParameters().Length); @@ -105,15 +103,13 @@ public static class EntityHelper continue; } - var areParametersCompatible = - expectedParameters - .All(expectedParameter => - parameters.Any(parameter => - !string.IsNullOrWhiteSpace(parameter.Name) && - parameter.Name.Equals(expectedParameter.Name, StringComparison.OrdinalIgnoreCase) && - ValueConverter.CanConvert(expectedParameter.Type, parameter.ParameterType) - ) - ); + var areParametersCompatible = expectedParameters.All(expectedParameter => + parameters.Any(parameter => + !string.IsNullOrWhiteSpace(parameter.Name) + && parameter.Name.Equals(expectedParameter.Name, StringComparison.OrdinalIgnoreCase) + && ValueConverter.CanConvert(expectedParameter.Type, parameter.ParameterType) + ) + ); if (areParametersCompatible) { @@ -135,12 +131,12 @@ public static class EntityHelper /// The type of which to find the parameterless constructor. /// is . public static ConstructorInfo? FindParameterlessConstructor( - [DynamicallyAccessedMembers(EntityMemberTypes)] Type type) + [DynamicallyAccessedMembers(EntityMemberTypes)] Type type + ) { ArgumentNullException.ThrowIfNull(type); - return type - .GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) + return type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .OrderByDescending(c => c.IsPublic) .ThenBy(c => c.IsPrivate) .FirstOrDefault(c => c.GetParameters().Length == 0); @@ -161,7 +157,8 @@ public static class EntityHelper /// There is more than one identity property defined for the entity type . /// public static EntityTypeMetadata GetEntityTypeMetadata( - [DynamicallyAccessedMembers(EntityMemberTypes)] Type entityType) + [DynamicallyAccessedMembers(EntityMemberTypes)] Type entityType + ) { ArgumentNullException.ThrowIfNull(entityType); @@ -180,8 +177,7 @@ public static EntityTypeMetadata GetEntityTypeMetadata( /// /// Resets the cached entity types metadata. /// - internal static void ResetEntityTypeMetadataCache() => - entityTypeMetadataPerEntityType.Clear(); + internal static void ResetEntityTypeMetadataCache() => entityTypeMetadataPerEntityType.Clear(); /// /// Creates the getter function for the property . @@ -240,11 +236,13 @@ internal static void ResetEntityTypeMetadataCache() => /// There is more than one identity property defined for the entity type . /// private static EntityTypeMetadata CreateEntityTypeMetadata( - [DynamicallyAccessedMembers(EntityMemberTypes)] Type entityType) + [DynamicallyAccessedMembers(EntityMemberTypes)] Type entityType + ) { string tableName; - DbConnectionPlusConfiguration.Instance.GetEntityTypeBuilders() + DbConnectionPlusConfiguration + .Instance.GetEntityTypeBuilders() .TryGetValue(entityType, out var entityTypeBuilder); if (entityTypeBuilder is not null) @@ -268,16 +266,14 @@ private static EntityTypeMetadata CreateEntityTypeMetadata( var property = properties[i]; if ( - entityTypeBuilder is not null && - entityTypeBuilder.PropertyBuilders.TryGetValue(property.Name, out var propertyBuilder) + entityTypeBuilder is not null + && entityTypeBuilder.PropertyBuilders.TryGetValue(property.Name, out var propertyBuilder) ) { propertiesMetadata[i] = new( property.CanRead, property.CanWrite, - !string.IsNullOrWhiteSpace(propertyBuilder.ColumnName) - ? propertyBuilder.ColumnName - : property.Name, + !string.IsNullOrWhiteSpace(propertyBuilder.ColumnName) ? propertyBuilder.ColumnName : property.Name, propertyBuilder.IsComputed, propertyBuilder.IsConcurrencyToken, propertyBuilder.IsIdentity, @@ -297,11 +293,11 @@ entityTypeBuilder is not null && property.CanRead, property.CanWrite, property.GetCustomAttribute()?.Name ?? property.Name, - property.GetCustomAttribute()?.DatabaseGeneratedOption is - DatabaseGeneratedOption.Computed, + property.GetCustomAttribute()?.DatabaseGeneratedOption + is DatabaseGeneratedOption.Computed, property.GetCustomAttribute() is not null, - property.GetCustomAttribute()?.DatabaseGeneratedOption is - DatabaseGeneratedOption.Identity, + property.GetCustomAttribute()?.DatabaseGeneratedOption + is DatabaseGeneratedOption.Identity, property.GetCustomAttribute() is not null, property.GetCustomAttribute() is not null, property.GetCustomAttribute() is not null, @@ -319,48 +315,58 @@ entityTypeBuilder is not null && if (identityProperties.Count > 1) { throw new InvalidOperationException( - $"There are multiple identity properties defined for the entity type {entityType}. Only one property " + - "can be marked as an identity property per entity type." + $"There are multiple identity properties defined for the entity type {entityType}. Only one property " + + "can be marked as an identity property per entity type." ); } IReadOnlyList computedProperties = - [.. propertiesMetadata.Where(p => p is { IsIgnored: false, IsComputed: true })]; + [ + .. propertiesMetadata.Where(p => p is { IsIgnored: false, IsComputed: true }), + ]; IReadOnlyList concurrencyTokenProperties = - [.. propertiesMetadata.Where(p => p is { IsIgnored: false, IsConcurrencyToken: true })]; + [ + .. propertiesMetadata.Where(p => p is { IsIgnored: false, IsConcurrencyToken: true }), + ]; IReadOnlyList databaseGeneratedProperties = - [.. propertiesMetadata.Where(p => !p.IsIgnored && (p.IsComputed || p.IsIdentity || p.IsRowVersion))]; + [ + .. propertiesMetadata.Where(p => !p.IsIgnored && (p.IsComputed || p.IsIdentity || p.IsRowVersion)), + ]; IReadOnlyList insertProperties = [ - .. propertiesMetadata.Where(p => p is - { IsIgnored: false, IsComputed: false, IsIdentity: false, IsRowVersion: false } - ) + .. propertiesMetadata.Where(p => + p is { IsIgnored: false, IsComputed: false, IsIdentity: false, IsRowVersion: false } + ), ]; IReadOnlyList keyProperties = - [.. propertiesMetadata.Where(p => p is { IsIgnored: false, IsKey: true })]; + [ + .. propertiesMetadata.Where(p => p is { IsIgnored: false, IsKey: true }), + ]; - IReadOnlyList mappedProperties = - [.. propertiesMetadata.Where(p => !p.IsIgnored)]; + IReadOnlyList mappedProperties = [.. propertiesMetadata.Where(p => !p.IsIgnored)]; IReadOnlyList rowVersionProperties = - [.. propertiesMetadata.Where(p => p is { IsIgnored: false, IsRowVersion: true })]; + [ + .. propertiesMetadata.Where(p => p is { IsIgnored: false, IsRowVersion: true }), + ]; IReadOnlyList updateProperties = [ - .. propertiesMetadata.Where(p => p is - { - IsComputed: false, - IsConcurrencyToken: false, - IsIgnored: false, - IsIdentity: false, - IsKey: false, - IsRowVersion: false - } - ) + .. propertiesMetadata.Where(p => + p + is { + IsComputed: false, + IsConcurrencyToken: false, + IsIgnored: false, + IsIdentity: false, + IsKey: false, + IsRowVersion: false + } + ), ]; return new( @@ -380,6 +386,5 @@ .. propertiesMetadata.Where(p => p is ); } - private static readonly - ConcurrentDictionary entityTypeMetadataPerEntityType = []; + private static readonly ConcurrentDictionary entityTypeMetadataPerEntityType = []; } diff --git a/src/DbConnectionPlus/EnumSerializationMode.cs b/src/DbConnectionPlus/EnumSerializationMode.cs index 20e11a9..0aaa3d4 100644 --- a/src/DbConnectionPlus/EnumSerializationMode.cs +++ b/src/DbConnectionPlus/EnumSerializationMode.cs @@ -16,5 +16,5 @@ public enum EnumSerializationMode /// /// values are serialized as strings. /// - Strings = 1 + Strings = 1, } diff --git a/src/DbConnectionPlus/Exceptions/DbUpdateConcurrencyException.cs b/src/DbConnectionPlus/Exceptions/DbUpdateConcurrencyException.cs index c6d224b..0298823 100644 --- a/src/DbConnectionPlus/Exceptions/DbUpdateConcurrencyException.cs +++ b/src/DbConnectionPlus/Exceptions/DbUpdateConcurrencyException.cs @@ -12,32 +12,28 @@ public class DbUpdateConcurrencyException : Exception /// /// The error message. /// The entity that was involved in the concurrency violation. - public DbUpdateConcurrencyException(string message, object entity) : base(message) => - this.Entity = entity; + public DbUpdateConcurrencyException(string message, object entity) + : base(message) => this.Entity = entity; /// /// Initializes a new instance of the class. /// - public DbUpdateConcurrencyException() - { - } + public DbUpdateConcurrencyException() { } /// /// Initializes a new instance of the class. /// /// The error message. - public DbUpdateConcurrencyException(string message) : base(message) - { - } + public DbUpdateConcurrencyException(string message) + : base(message) { } /// /// Initializes a new instance of the class. /// /// The error message. /// The inner exception. - public DbUpdateConcurrencyException(string message, Exception innerException) : base(message, innerException) - { - } + public DbUpdateConcurrencyException(string message, Exception innerException) + : base(message, innerException) { } /// /// The entity that was involved in the concurrency violation. diff --git a/src/DbConnectionPlus/Extensions/Int32Extensions.cs b/src/DbConnectionPlus/Extensions/Int32Extensions.cs index bab73d5..2516a9a 100644 --- a/src/DbConnectionPlus/Extensions/Int32Extensions.cs +++ b/src/DbConnectionPlus/Extensions/Int32Extensions.cs @@ -16,8 +16,7 @@ internal static class Int32Extensions /// /// The number to ordinalize. /// The ordinalized number in english notation. - internal static string OrdinalizeEnglish(this int value) => - value.Ordinalize(englishCulture); + internal static string OrdinalizeEnglish(this int value) => value.Ordinalize(englishCulture); private static readonly CultureInfo englishCulture = new("en-US"); } diff --git a/src/DbConnectionPlus/Extensions/ObjectExtensions.cs b/src/DbConnectionPlus/Extensions/ObjectExtensions.cs index ed98c2b..609a5c8 100644 --- a/src/DbConnectionPlus/Extensions/ObjectExtensions.cs +++ b/src/DbConnectionPlus/Extensions/ObjectExtensions.cs @@ -26,7 +26,7 @@ internal static string ToDebugString(this object? value) => { null => "{null}", DBNull => "{DBNull}", - _ => $"'{FormatValue(value, 0)}' ({value.GetType()})" + _ => $"'{FormatValue(value, 0)}' ({value.GetType()})", }; /// @@ -38,88 +38,62 @@ internal static string ToDebugString(this object? value) => private static string FormatValue(object? value, int depth) => value switch { - null => - "{null}", + null => "{null}", - DBNull => - "{DBNull}", + DBNull => "{DBNull}", - bool booleanValue => - booleanValue ? "True" : "False", + bool booleanValue => booleanValue ? "True" : "False", - byte byteValue => - byteValue.ToString("G", CultureInfo.InvariantCulture), + byte byteValue => byteValue.ToString("G", CultureInfo.InvariantCulture), - byte[] bytesValue => - Convert.ToBase64String(bytesValue), + byte[] bytesValue => Convert.ToBase64String(bytesValue), - char charValue => - charValue.ToString(), + char charValue => charValue.ToString(), - DateTime dateTimeValue => - dateTimeValue.ToString("O", CultureInfo.InvariantCulture), + DateTime dateTimeValue => dateTimeValue.ToString("O", CultureInfo.InvariantCulture), - DateTimeOffset dateTimeOffsetValue => - dateTimeOffsetValue.ToString("O", CultureInfo.InvariantCulture), + DateTimeOffset dateTimeOffsetValue => dateTimeOffsetValue.ToString("O", CultureInfo.InvariantCulture), - decimal decimalValue => - decimalValue.ToString("N", CultureInfo.InvariantCulture), + decimal decimalValue => decimalValue.ToString("N", CultureInfo.InvariantCulture), - double doubleValue => - doubleValue.ToString("G17", CultureInfo.InvariantCulture), + double doubleValue => doubleValue.ToString("G17", CultureInfo.InvariantCulture), - Enum enumValue => - enumValue.ToString(), + Enum enumValue => enumValue.ToString(), - Guid guidValue => - guidValue.ToString("D", CultureInfo.InvariantCulture), + Guid guidValue => guidValue.ToString("D", CultureInfo.InvariantCulture), - short int16Value => - int16Value.ToString("G", CultureInfo.InvariantCulture), + short int16Value => int16Value.ToString("G", CultureInfo.InvariantCulture), - int int32Value => - int32Value.ToString("G", CultureInfo.InvariantCulture), + int int32Value => int32Value.ToString("G", CultureInfo.InvariantCulture), - long int64Value => - int64Value.ToString("G", CultureInfo.InvariantCulture), + long int64Value => int64Value.ToString("G", CultureInfo.InvariantCulture), - IntPtr intPtrValue => - intPtrValue.ToString("G", CultureInfo.InvariantCulture), + IntPtr intPtrValue => intPtrValue.ToString("G", CultureInfo.InvariantCulture), - sbyte sbyteValue => - sbyteValue.ToString("G", CultureInfo.InvariantCulture), + sbyte sbyteValue => sbyteValue.ToString("G", CultureInfo.InvariantCulture), - float singleValue => - singleValue.ToString("G9", CultureInfo.InvariantCulture), + float singleValue => singleValue.ToString("G9", CultureInfo.InvariantCulture), - string stringValue => - stringValue, + string stringValue => stringValue, - TimeSpan timeSpanValue => - timeSpanValue.ToString("c", CultureInfo.InvariantCulture), + TimeSpan timeSpanValue => timeSpanValue.ToString("c", CultureInfo.InvariantCulture), - ushort uint16Value => - uint16Value.ToString("G", CultureInfo.InvariantCulture), + ushort uint16Value => uint16Value.ToString("G", CultureInfo.InvariantCulture), - uint uint32Value => - uint32Value.ToString("G", CultureInfo.InvariantCulture), + uint uint32Value => uint32Value.ToString("G", CultureInfo.InvariantCulture), - ulong uint64Value => - uint64Value.ToString("G", CultureInfo.InvariantCulture), + ulong uint64Value => uint64Value.ToString("G", CultureInfo.InvariantCulture), - UIntPtr uintPtrValue => - uintPtrValue.ToString("G", CultureInfo.InvariantCulture), + UIntPtr uintPtrValue => uintPtrValue.ToString("G", CultureInfo.InvariantCulture), // Must stay below the Byte[] and String arms above, both of which are sequences that have // a more useful representation of their own. - IEnumerable sequenceValue => - FormatSequence(sequenceValue, depth), + IEnumerable sequenceValue => FormatSequence(sequenceValue, depth), // Deliberately not JsonSerializer.Serialize: the reflection-based JsonSerializer overloads // are unavailable under Native AOT, so a conversion error would itself fail while building // its message. A type that renders as its own name here simply has no ToString override. - _ => - value.ToString() ?? string.Empty + _ => value.ToString() ?? string.Empty, }; /// diff --git a/src/DbConnectionPlus/Extensions/TypeExtensions.cs b/src/DbConnectionPlus/Extensions/TypeExtensions.cs index df1178e..3ce2af8 100644 --- a/src/DbConnectionPlus/Extensions/TypeExtensions.cs +++ b/src/DbConnectionPlus/Extensions/TypeExtensions.cs @@ -116,7 +116,7 @@ internal static bool IsValueTupleType(this Type type) typeof(DateTimeOffset), typeof(TimeSpan), typeof(TimeOnly), - typeof(Guid) + typeof(Guid), ]; private static readonly HashSet valueTupleTypes = @@ -128,6 +128,6 @@ internal static bool IsValueTupleType(this Type type) typeof(ValueTuple<,,,,>), typeof(ValueTuple<,,,,,>), typeof(ValueTuple<,,,,,,>), - typeof(ValueTuple<,,,,,,,>) + typeof(ValueTuple<,,,,,,,>), ]; } diff --git a/src/DbConnectionPlus/Helpers/NameHelper.cs b/src/DbConnectionPlus/Helpers/NameHelper.cs index 75de15c..769d897 100644 --- a/src/DbConnectionPlus/Helpers/NameHelper.cs +++ b/src/DbConnectionPlus/Helpers/NameHelper.cs @@ -57,9 +57,12 @@ internal static string CreateNameFromCallerArgumentExpression(ReadOnlySpan var character = Unsafe.Add(ref expressionPointer, i); if ( - (uint)(character - '0') <= 9 || // Digits - (uint)(character - 'A') <= 25 || // Uppercase letters - (uint)(character - 'a') <= 25 || // Lowercase letters + (uint)(character - '0') <= 9 + || // Digits + (uint)(character - 'A') <= 25 + || // Uppercase letters + (uint)(character - 'a') <= 25 + || // Lowercase letters character == '_' ) { diff --git a/src/DbConnectionPlus/Materializers/EntityMaterializerFactory.cs b/src/DbConnectionPlus/Materializers/EntityMaterializerFactory.cs index f18cb7a..f2feb72 100644 --- a/src/DbConnectionPlus/Materializers/EntityMaterializerFactory.cs +++ b/src/DbConnectionPlus/Materializers/EntityMaterializerFactory.cs @@ -25,9 +25,9 @@ internal static class EntityMaterializerFactory /// verifies that guard rather than so that a warning propagates. /// private const string MaterializerRequiresDynamicCodeMessage = - "Materializing entities compiles an expression tree at run time, which is not supported when the " + - "application is published with Native AOT. Reach this only from a RuntimeFeature.IsDynamicCodeSupported " + - "branch."; + "Materializing entities compiles an expression tree at run time, which is not supported when the " + + "application is published with Native AOT. Reach this only from a RuntimeFeature.IsDynamicCodeSupported " + + "branch."; /// /// Gets a materializer function that materializes the data in a to an instance of the @@ -183,11 +183,7 @@ internal static Func GetMaterializer< /// internal static Func CreateReflectionMaterializer< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( - DbDataReader dataReader, - string[] dataReaderFieldNames, - Type[] dataReaderFieldTypes - ) + >(DbDataReader dataReader, string[] dataReaderFieldNames, Type[] dataReaderFieldTypes) { ArgumentNullException.ThrowIfNull(dataReader); ArgumentNullException.ThrowIfNull(dataReaderFieldNames); @@ -195,17 +191,11 @@ Type[] dataReaderFieldTypes var compatibleConstructor = EntityHelper.FindCompatibleConstructor( typeof(TEntity), - [ - .. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) - ] + [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type))] ); return compatibleConstructor is null - ? CreateReflectionPropertyMaterializer( - dataReader, - dataReaderFieldNames, - dataReaderFieldTypes - ) + ? CreateReflectionPropertyMaterializer(dataReader, dataReaderFieldNames, dataReaderFieldTypes) : CreateReflectionConstructorMaterializer( dataReader, dataReaderFieldNames, @@ -262,9 +252,9 @@ ConstructorInfo compatibleConstructor var dataReaderFieldType = dataReaderFieldTypes[fieldOrdinal]; var constructorParameter = constructorParameters.First(p => - !string.IsNullOrWhiteSpace(p.Name) && - p.Name.Equals(dataReaderFieldName, StringComparison.OrdinalIgnoreCase) && - ValueConverter.CanConvert(dataReaderFieldType, p.ParameterType) + !string.IsNullOrWhiteSpace(p.Name) + && p.Name.Equals(dataReaderFieldName, StringComparison.OrdinalIgnoreCase) + && ValueConverter.CanConvert(dataReaderFieldType, p.ParameterType) ); constructorArgumentBindings[Array.IndexOf(constructorParameters, constructorParameter)] = @@ -283,12 +273,13 @@ ConstructorInfo compatibleConstructor var entityConstructor = ConstructorInvoker.Create(compatibleConstructor); - return rowDataReader => MaterializeEntityThroughConstructor( - rowDataReader, - entityType, - entityConstructor, - constructorArgumentBindings - ); + return rowDataReader => + MaterializeEntityThroughConstructor( + rowDataReader, + entityType, + entityConstructor, + constructorArgumentBindings + ); } /// @@ -317,15 +308,12 @@ ConstructorInfo compatibleConstructor /// private static Func CreateReflectionPropertyMaterializer< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( - DbDataReader dataReader, - string[] dataReaderFieldNames, - Type[] dataReaderFieldTypes - ) + >(DbDataReader dataReader, string[] dataReaderFieldNames, Type[] dataReaderFieldTypes) { var entityType = typeof(TEntity); - var entityPropertiesByColumnName = EntityHelper.GetEntityTypeMetadata(entityType) + var entityPropertiesByColumnName = EntityHelper + .GetEntityTypeMetadata(entityType) .MappedProperties.Where(a => a.CanWrite) .ToDictionary(a => a.ColumnName, StringComparer.OrdinalIgnoreCase); @@ -368,12 +356,13 @@ Type[] dataReaderFieldTypes var resolvedPropertyBindings = propertyBindings.ToArray(); - return rowDataReader => MaterializeEntityThroughProperties( - rowDataReader, - entityType, - entityConstructor, - resolvedPropertyBindings - ); + return rowDataReader => + MaterializeEntityThroughProperties( + rowDataReader, + entityType, + entityConstructor, + resolvedPropertyBindings + ); } /// @@ -415,13 +404,13 @@ Dictionary entityPropertiesByColumnName } throw new InvalidOperationException( - $"None of the {dataReaderFieldNames.Length} field(s) of the result set " + - $"({string.Join(", ", dataReaderFieldNames)}) could be mapped to a writable property of the entity " + - $"type {entityType}. Materializing the result set would return entities whose properties are all left " + - "at their default values. Check that the field names of the result set match the property names, or " + - "the mapped column names, of the entity type. If the application is trimmed or published with Native " + - "AOT, this usually means the properties of the entity type were removed by the trimmer because a " + - "[DynamicallyAccessedMembers] annotation is missing on the call path." + $"None of the {dataReaderFieldNames.Length} field(s) of the result set " + + $"({string.Join(", ", dataReaderFieldNames)}) could be mapped to a writable property of the entity " + + $"type {entityType}. Materializing the result set would return entities whose properties are all left " + + "at their default values. Check that the field names of the result set match the property names, or " + + "the mapped column names, of the entity type. If the application is trimmed or published with Native " + + "AOT, this usually means the properties of the entity type were removed by the trimmer because a " + + "[DynamicallyAccessedMembers] annotation is missing on the call path." ); } @@ -489,16 +478,13 @@ Dictionary entityPropertiesByColumnName [UnconditionalSuppressMessage( "AOT", "IL3050:Requires dynamic code", - Justification = - "The call is inside an if (RuntimeFeature.IsDynamicCodeSupported) branch, which the AOT compiler folds " + - "to false and removes together with the expression-tree implementation. The net9.0+ analyzer " + - "recognizes that guard and reports nothing here; net8.0 lacks the [FeatureGuard] annotation on " + - "IsDynamicCodeSupported that lets it do so." + Justification = "The call is inside an if (RuntimeFeature.IsDynamicCodeSupported) branch, which the AOT compiler folds " + + "to false and removes together with the expression-tree implementation. The net9.0+ analyzer " + + "recognizes that guard and reports nothing here; net8.0 lacks the [FeatureGuard] annotation on " + + "IsDynamicCodeSupported that lets it do so." )] #endif - private static Delegate CreateMaterializer< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( + private static Delegate CreateMaterializer<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbDataReader dataReader, string[] dataReaderFieldNames, Type[] dataReaderFieldTypes @@ -519,7 +505,8 @@ [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) GuardAgainstResultSetBindingNoProperties( entityType, dataReaderFieldNames, - EntityHelper.GetEntityTypeMetadata(entityType) + EntityHelper + .GetEntityTypeMetadata(entityType) .MappedProperties.Where(a => a.CanWrite) .ToDictionary(a => a.ColumnName, StringComparer.OrdinalIgnoreCase) ); @@ -562,11 +549,7 @@ [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) [RequiresDynamicCode(MaterializerRequiresDynamicCodeMessage)] private static Delegate CreateExpressionMaterializer< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >( - DbDataReader dataReader, - string[] dataReaderFieldNames, - Type[] dataReaderFieldTypes - ) + >(DbDataReader dataReader, string[] dataReaderFieldNames, Type[] dataReaderFieldTypes) { var entityType = typeof(TEntity); @@ -588,7 +571,8 @@ Type[] dataReaderFieldTypes [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type))] ); - var entityPropertiesByColumnName = EntityHelper.GetEntityTypeMetadata(entityType) + var entityPropertiesByColumnName = EntityHelper + .GetEntityTypeMetadata(entityType) .MappedProperties.Where(a => a.CanWrite) .ToDictionary(a => a.ColumnName, StringComparer.OrdinalIgnoreCase); @@ -599,9 +583,9 @@ [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) for (var fieldOrdinal = 0; fieldOrdinal < dataReader.FieldCount; fieldOrdinal++) { var constructorParameter = constructorParameters.First(p => - !string.IsNullOrWhiteSpace(p.Name) && - p.Name.Equals(dataReaderFieldNames[fieldOrdinal], StringComparison.OrdinalIgnoreCase) && - ValueConverter.CanConvert(dataReaderFieldTypes[fieldOrdinal], p.ParameterType) + !string.IsNullOrWhiteSpace(p.Name) + && p.Name.Equals(dataReaderFieldNames[fieldOrdinal], StringComparison.OrdinalIgnoreCase) + && ValueConverter.CanConvert(dataReaderFieldTypes[fieldOrdinal], p.ParameterType) ); fieldOrdinalToConstructorParameterIndex.Add( @@ -620,17 +604,11 @@ [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) if (entityPropertiesByColumnName.TryGetValue(dataReaderFieldName, out var entityProperty)) { - fieldOrdinalToTargetType.Add( - fieldOrdinal, - entityProperty.PropertyType - ); + fieldOrdinalToTargetType.Add(fieldOrdinal, entityProperty.PropertyType); } else { - fieldOrdinalToTargetType.Add( - fieldOrdinal, - dataReaderFieldTypes[fieldOrdinal] - ); + fieldOrdinalToTargetType.Add(fieldOrdinal, dataReaderFieldTypes[fieldOrdinal]); } } } @@ -703,9 +681,9 @@ [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) Expression.New( typeof(InvalidCastException).GetConstructor([typeof(string)])!, Expression.Constant( - $"The column '{dataReaderFieldName}' returned by the SQL statement contains a " + - $"NULL value, but the corresponding property of the type {entityType} is " + - "non-nullable." + $"The column '{dataReaderFieldName}' returned by the SQL statement contains a " + + $"NULL value, but the corresponding property of the type {entityType} is " + + "non-nullable." ) ), targetType @@ -713,14 +691,12 @@ [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) var throwInvalidCastExceptionExpression = Expression.Throw( Expression.New( - typeof(InvalidCastException).GetConstructor( - [typeof(string), typeof(Exception)] - )!, + typeof(InvalidCastException).GetConstructor([typeof(string), typeof(Exception)])!, Expression.Constant( - $"The column '{dataReaderFieldName}' returned by the SQL statement " + - $"contains a value that could not be converted to the type {targetType} " + - $"of the corresponding property of the type {entityType}. See inner " + - "exception for details." + $"The column '{dataReaderFieldName}' returned by the SQL statement " + + $"contains a value that could not be converted to the type {targetType} " + + $"of the corresponding property of the type {entityType}. See inner " + + "exception for details." ), exceptionParameterExpression ), @@ -736,26 +712,21 @@ [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) ), targetType ), - Expression.Catch( - exceptionParameterExpression, - throwInvalidCastExceptionExpression - ) + Expression.Catch(exceptionParameterExpression, throwInvalidCastExceptionExpression) ); - var isNotDbNullBranchExpression = dataReaderFieldType != targetType - ? convertFieldValueExpression - : getFieldValueCallExpression; + var isNotDbNullBranchExpression = + dataReaderFieldType != targetType ? convertFieldValueExpression : getFieldValueCallExpression; - dataReaderFieldValueExpressions[fieldOrdinal] = - Expression.Condition( - Expression.Call( - dataReaderParameterExpression, - MaterializerFactoryHelper.DbDataReaderIsDBNullMethod, - fieldOrdinalExpression - ), - isDbNullBranchExpression, - isNotDbNullBranchExpression - ); + dataReaderFieldValueExpressions[fieldOrdinal] = Expression.Condition( + Expression.Call( + dataReaderParameterExpression, + MaterializerFactoryHelper.DbDataReaderIsDBNullMethod, + fieldOrdinalExpression + ), + isDbNullBranchExpression, + isNotDbNullBranchExpression + ); } Expression bodyExpression; @@ -768,8 +739,9 @@ [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) { var constructorArgumentIndex = fieldOrdinalToConstructorParameterIndex[fieldOrdinal]; - constructorArgumentExpressions[constructorArgumentIndex] = - dataReaderFieldValueExpressions[fieldOrdinal]; + constructorArgumentExpressions[constructorArgumentIndex] = dataReaderFieldValueExpressions[ + fieldOrdinal + ]; } // Basically: @@ -831,8 +803,11 @@ ReflectionColumnBinding[] constructorArgumentBindings for (var argumentIndex = 0; argumentIndex < constructorArgumentBindings.Length; argumentIndex++) { - constructorArguments[argumentIndex] = - ReadFieldValue(dataReader, entityType, constructorArgumentBindings[argumentIndex]); + constructorArguments[argumentIndex] = ReadFieldValue( + dataReader, + entityType, + constructorArgumentBindings[argumentIndex] + ); } return (TEntity)entityConstructor.Invoke(constructorArguments.AsSpan()); @@ -904,8 +879,8 @@ ReflectionColumnBinding columnBinding } throw new InvalidCastException( - $"The column '{columnBinding.FieldName}' returned by the SQL statement contains a NULL value, but " + - $"the corresponding property of the type {entityType} is non-nullable." + $"The column '{columnBinding.FieldName}' returned by the SQL statement contains a NULL value, but " + + $"the corresponding property of the type {entityType} is non-nullable." ); } @@ -923,9 +898,9 @@ ReflectionColumnBinding columnBinding catch (Exception exception) { throw new InvalidCastException( - $"The column '{columnBinding.FieldName}' returned by the SQL statement contains a value that could " + - $"not be converted to the type {columnBinding.TargetType} of the corresponding property of the " + - $"type {entityType}. See inner exception for details.", + $"The column '{columnBinding.FieldName}' returned by the SQL statement contains a value that could " + + $"not be converted to the type {columnBinding.TargetType} of the corresponding property of the " + + $"type {entityType}. See inner exception for details.", exception ); } @@ -990,8 +965,8 @@ Type[] dataReaderFieldTypes if (string.IsNullOrWhiteSpace(dataReaderFieldName)) { throw new ArgumentException( - $"The {(fieldOrdinal + 1).OrdinalizeEnglish()} column returned by the SQL statement does not " + - "have a name. Make sure that all columns the statement returns have a name.", + $"The {(fieldOrdinal + 1).OrdinalizeEnglish()} column returned by the SQL statement does not " + + "have a name. Make sure that all columns the statement returns have a name.", nameof(dataReader) ); } @@ -999,8 +974,8 @@ Type[] dataReaderFieldTypes if (!MaterializerFactoryHelper.IsDbDataReaderTypedGetMethodAvailable(dataReaderFieldType)) { throw new ArgumentException( - $"The data type {dataReaderFieldType} of the column '{dataReaderFieldName}' returned by the " + - "SQL statement is not supported.", + $"The data type {dataReaderFieldType} of the column '{dataReaderFieldName}' returned by the " + + "SQL statement is not supported.", nameof(dataReader) ); } @@ -1023,23 +998,24 @@ [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) if (parameterlessConstructor is null) { var exampleConstructorSignature = - "(" + - string.Join( + "(" + + string.Join( ", ", dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => $"{type.Name} {name}") - ) + - ")"; + ) + + ")"; throw new ArgumentException( - $"Could not materialize an instance of the type {entityType}. The type either needs to have a " + - "parameterless constructor or a constructor whose parameters match the columns returned by the SQL " + - $"statement, e.g. a constructor that has the following signature:{Environment.NewLine}" + - $"{exampleConstructorSignature}.", + $"Could not materialize an instance of the type {entityType}. The type either needs to have a " + + "parameterless constructor or a constructor whose parameters match the columns returned by the SQL " + + $"statement, e.g. a constructor that has the following signature:{Environment.NewLine}" + + $"{exampleConstructorSignature}.", nameof(entityType) ); } - var entityPropertiesByColumnName = EntityHelper.GetEntityTypeMetadata(entityType) + var entityPropertiesByColumnName = EntityHelper + .GetEntityTypeMetadata(entityType) .MappedProperties.Where(a => a.CanWrite) .ToDictionary(a => a.ColumnName, StringComparer.OrdinalIgnoreCase); @@ -1058,9 +1034,9 @@ [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) if (!ValueConverter.CanConvert(dataReaderFieldType, entityPropertyType)) { throw new ArgumentException( - $"The data type {dataReaderFieldType} of the column '{dataReaderFieldName}' returned by the " + - $"SQL statement is not compatible with the property type {entityPropertyType} of the " + - $"corresponding property of the type {entityType}.", + $"The data type {dataReaderFieldType} of the column '{dataReaderFieldName}' returned by the " + + $"SQL statement is not compatible with the property type {entityPropertyType} of the " + + $"corresponding property of the type {entityType}.", nameof(dataReader) ); } @@ -1085,8 +1061,7 @@ private readonly struct MaterializerCacheKey( Type entityType, string[] dataReaderFieldNames, Type[] dataReaderFieldTypes - ) - : IEquatable + ) : IEquatable { /// /// The type of entity the materializer materializes. @@ -1095,13 +1070,12 @@ Type[] dataReaderFieldTypes /// public bool Equals(MaterializerCacheKey other) => - this.EntityType == other.EntityType && - this.DataReaderFieldNames.SequenceEqual(other.DataReaderFieldNames) && - this.DataReaderFieldTypes.SequenceEqual(other.DataReaderFieldTypes); + this.EntityType == other.EntityType + && this.DataReaderFieldNames.SequenceEqual(other.DataReaderFieldNames) + && this.DataReaderFieldTypes.SequenceEqual(other.DataReaderFieldTypes); /// - public override bool Equals(object? obj) => - obj is MaterializerCacheKey other && this.Equals(other); + public override bool Equals(object? obj) => obj is MaterializerCacheKey other && this.Equals(other); /// public override int GetHashCode() diff --git a/src/DbConnectionPlus/Materializers/MaterializerFactoryHelper.cs b/src/DbConnectionPlus/Materializers/MaterializerFactoryHelper.cs index adc8c24..d629565 100644 --- a/src/DbConnectionPlus/Materializers/MaterializerFactoryHelper.cs +++ b/src/DbConnectionPlus/Materializers/MaterializerFactoryHelper.cs @@ -16,33 +16,33 @@ internal static class MaterializerFactoryHelper /// /// The method. /// - internal static MethodInfo DbDataReaderGetValueMethod { get; } = typeof(DbDataReader) - .GetMethod(nameof(DbDataReader.GetValue))!; + internal static MethodInfo DbDataReaderGetValueMethod { get; } = + typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetValue))!; /// /// The method. /// // ReSharper disable once InconsistentNaming - internal static MethodInfo DbDataReaderIsDBNullMethod { get; } = typeof(DbDataReader) - .GetMethod(nameof(DbDataReader.IsDBNull))!; + internal static MethodInfo DbDataReaderIsDBNullMethod { get; } = + typeof(DbDataReader).GetMethod(nameof(DbDataReader.IsDBNull))!; /// /// The 'Chars' property of the type. /// - internal static PropertyInfo StringCharsProperty { get; } = typeof(string) - .GetProperty("Chars", BindingFlags.Instance | BindingFlags.Public)!; + internal static PropertyInfo StringCharsProperty { get; } = + typeof(string).GetProperty("Chars", BindingFlags.Instance | BindingFlags.Public)!; /// /// The method. /// - internal static MethodInfo StringConcatMethod { get; } = typeof(string) - .GetMethod(nameof(String.Concat), [typeof(string), typeof(string), typeof(string)])!; + internal static MethodInfo StringConcatMethod { get; } = + typeof(string).GetMethod(nameof(String.Concat), [typeof(string), typeof(string), typeof(string)])!; /// /// The property. /// - internal static PropertyInfo StringLengthProperty { get; } = typeof(string) - .GetProperty(nameof(String.Length), BindingFlags.Instance | BindingFlags.Public)!; + internal static PropertyInfo StringLengthProperty { get; } = + typeof(string).GetProperty(nameof(String.Length), BindingFlags.Instance | BindingFlags.Public)!; /// /// Specializes over , so that @@ -75,16 +75,15 @@ internal static class MaterializerFactoryHelper /// /// [RequiresDynamicCode( - "Specializing a generic method over a value type at run time is not supported when the application is " + - "published with Native AOT. Call this only from a RuntimeFeature.IsDynamicCodeSupported branch." + "Specializing a generic method over a value type at run time is not supported when the application is " + + "published with Native AOT. Call this only from a RuntimeFeature.IsDynamicCodeSupported branch." )] [UnconditionalSuppressMessage( "Trimming", "IL2060:MakeGenericMethod call cannot be statically analyzed", - Justification = - "ValueConverter.ConvertValueToType declares no DynamicallyAccessedMembers on TTarget, so the " + - "specialized instantiation has no requirements that trimming could fail to preserve. Reaching this " + - "method at all requires a RuntimeFeature.IsDynamicCodeSupported branch." + Justification = "ValueConverter.ConvertValueToType declares no DynamicallyAccessedMembers on TTarget, so the " + + "specialized instantiation has no requirements that trimming could fail to preserve. Reaching this " + + "method at all requires a RuntimeFeature.IsDynamicCodeSupported branch." )] internal static MethodInfo MakeValueConverterConvertValueToTypeMethod(Type targetType) => valueConverterConvertValueToTypeMethod.MakeGenericMethod(targetType); @@ -141,75 +140,50 @@ Type fieldType { // Special handling for byte arrays since DbDataReader does not have a GetBytes method that returns // a byte array directly. - return - Expression.Convert( - Expression.Call( - dataReaderExpression, - DbDataReaderGetValueMethod, - fieldOrdinalExpression - ), - typeof(byte[]) - ); + return Expression.Convert( + Expression.Call(dataReaderExpression, DbDataReaderGetValueMethod, fieldOrdinalExpression), + typeof(byte[]) + ); } if (fieldType == typeof(TimeSpan)) { // Special handling for the type TimeSpan since DbDataReader does not have a GetTimeSpan method that // returns a TimeSpan directly. - return - Expression.Convert( - Expression.Call( - dataReaderExpression, - DbDataReaderGetValueMethod, - fieldOrdinalExpression - ), - typeof(TimeSpan) - ); + return Expression.Convert( + Expression.Call(dataReaderExpression, DbDataReaderGetValueMethod, fieldOrdinalExpression), + typeof(TimeSpan) + ); } if (fieldType == typeof(TimeOnly)) { // Special handling for the type TimeOnly since DbDataReader does not have a GetTimeOnly method that // returns a TimeOnly directly. - return - Expression.Convert( - Expression.Call( - dataReaderExpression, - DbDataReaderGetValueMethod, - fieldOrdinalExpression - ), - typeof(TimeOnly) - ); + return Expression.Convert( + Expression.Call(dataReaderExpression, DbDataReaderGetValueMethod, fieldOrdinalExpression), + typeof(TimeOnly) + ); } if (fieldType == typeof(DateOnly)) { // Special handling for the type DateOnly since DbDataReader does not have a GetDateOnly method // that returns a DateOnly directly. - return - Expression.Convert( - Expression.Call( - dataReaderExpression, - DbDataReaderGetValueMethod, - fieldOrdinalExpression - ), - typeof(DateOnly) - ); + return Expression.Convert( + Expression.Call(dataReaderExpression, DbDataReaderGetValueMethod, fieldOrdinalExpression), + typeof(DateOnly) + ); } if (fieldType == typeof(DateTimeOffset)) { // Special handling for the type DateTimeOffset since DbDataReader does not have a GetDateTimeOffset method // that returns a DateTimeOffset directly. - return - Expression.Convert( - Expression.Call( - dataReaderExpression, - DbDataReaderGetValueMethod, - fieldOrdinalExpression - ), - typeof(DateTimeOffset) - ); + return Expression.Convert( + Expression.Call(dataReaderExpression, DbDataReaderGetValueMethod, fieldOrdinalExpression), + typeof(DateTimeOffset) + ); } if (!dbDataReaderTypedGetMethods.TryGetValue(fieldType, out var dbDataReaderGetMethod)) @@ -217,24 +191,20 @@ Type fieldType if (!string.IsNullOrWhiteSpace(fieldName)) { throw new ArgumentException( - $"The data type {fieldType} of the column '{fieldName}' returned by the SQL statement is not " + - "supported.", + $"The data type {fieldType} of the column '{fieldName}' returned by the SQL statement is not " + + "supported.", nameof(fieldType) ); } throw new ArgumentException( - $"The data type {fieldType} of the {(fieldOrdinal + 1).OrdinalizeEnglish()} column returned by the " + - "SQL statement is not supported.", + $"The data type {fieldType} of the {(fieldOrdinal + 1).OrdinalizeEnglish()} column returned by the " + + "SQL statement is not supported.", nameof(fieldType) ); } - return Expression.Call( - dataReaderExpression, - dbDataReaderGetMethod, - fieldOrdinalExpression - ); + return Expression.Call(dataReaderExpression, dbDataReaderGetMethod, fieldOrdinalExpression); } /// @@ -282,15 +252,15 @@ Type fieldType if (!string.IsNullOrWhiteSpace(fieldName)) { throw new ArgumentException( - $"The data type {fieldType} of the column '{fieldName}' returned by the SQL statement is not " + - "supported.", + $"The data type {fieldType} of the column '{fieldName}' returned by the SQL statement is not " + + "supported.", nameof(fieldType) ); } throw new ArgumentException( - $"The data type {fieldType} of the {(fieldOrdinal + 1).OrdinalizeEnglish()} column returned by the " + - "SQL statement is not supported.", + $"The data type {fieldType} of the {(fieldOrdinal + 1).OrdinalizeEnglish()} column returned by the " + + "SQL statement is not supported.", nameof(fieldType) ); } @@ -312,8 +282,7 @@ internal static bool IsDbDataReaderTypedGetMethodAvailable(Type fieldType) { ArgumentNullException.ThrowIfNull(fieldType); - return dbDataReaderTypedGetMethods.ContainsKey(fieldType) || - dbDataReaderUntypedFieldTypes.Contains(fieldType); + return dbDataReaderTypedGetMethods.ContainsKey(fieldType) || dbDataReaderUntypedFieldTypes.Contains(fieldType); } private static readonly Dictionary dbDataReaderTypedGetMethods = new() @@ -328,7 +297,7 @@ internal static bool IsDbDataReaderTypedGetMethodAvailable(Type fieldType) { typeof(short), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetInt16))! }, { typeof(int), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetInt32))! }, { typeof(long), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetInt64))! }, - { typeof(string), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetString))! } + { typeof(string), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetString))! }, }; /// @@ -352,7 +321,7 @@ internal static bool IsDbDataReaderTypedGetMethodAvailable(Type fieldType) { typeof(short), static (dataReader, fieldOrdinal) => dataReader.GetInt16(fieldOrdinal) }, { typeof(int), static (dataReader, fieldOrdinal) => dataReader.GetInt32(fieldOrdinal) }, { typeof(long), static (dataReader, fieldOrdinal) => dataReader.GetInt64(fieldOrdinal) }, - { typeof(string), static (dataReader, fieldOrdinal) => dataReader.GetString(fieldOrdinal) } + { typeof(string), static (dataReader, fieldOrdinal) => dataReader.GetString(fieldOrdinal) }, }; /// @@ -366,7 +335,7 @@ internal static bool IsDbDataReaderTypedGetMethodAvailable(Type fieldType) typeof(DateOnly), typeof(DateTimeOffset), typeof(TimeOnly), - typeof(TimeSpan) + typeof(TimeSpan), ]; /// diff --git a/src/DbConnectionPlus/Materializers/ValueTupleMaterializerFactory.cs b/src/DbConnectionPlus/Materializers/ValueTupleMaterializerFactory.cs index 060161a..7ea77f3 100644 --- a/src/DbConnectionPlus/Materializers/ValueTupleMaterializerFactory.cs +++ b/src/DbConnectionPlus/Materializers/ValueTupleMaterializerFactory.cs @@ -26,9 +26,9 @@ internal static class ValueTupleMaterializerFactory /// verifies that guard rather than so that a warning propagates. /// internal const string MaterializerRequiresDynamicCodeMessage = - "Materializing value tuples compiles an expression tree at run time, which is not supported when the " + - "application is published with Native AOT. Reach this only from a RuntimeFeature.IsDynamicCodeSupported " + - "branch."; + "Materializing value tuples compiles an expression tree at run time, which is not supported when the " + + "application is published with Native AOT. Reach this only from a RuntimeFeature.IsDynamicCodeSupported " + + "branch."; /// /// The members of a value tuple type that this library reflects over, and which therefore must survive trimming. @@ -53,8 +53,7 @@ internal static class ValueTupleMaterializerFactory /// /// internal const DynamicallyAccessedMemberTypes ValueTupleMemberTypes = - DynamicallyAccessedMemberTypes.PublicFields | - DynamicallyAccessedMemberTypes.PublicConstructors; + DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicConstructors; /// /// The number of fields a value tuple holds before the runtime represents the remaining ones as a nested value @@ -230,11 +229,7 @@ internal static Func GetMaterializer< /// internal static Func CreateReflectionMaterializer< [DynamicallyAccessedMembers(ValueTupleMemberTypes)] TValueTuple - >( - DbDataReader dataReader, - string[] dataReaderFieldNames, - Type[] dataReaderFieldTypes - ) + >(DbDataReader dataReader, string[] dataReaderFieldNames, Type[] dataReaderFieldTypes) { ArgumentNullException.ThrowIfNull(dataReader); ArgumentNullException.ThrowIfNull(dataReaderFieldNames); @@ -271,12 +266,8 @@ Type[] dataReaderFieldTypes .Select(ConstructorInvoker.Create) .ToArray(); - return rowDataReader => MaterializeValueTuple( - rowDataReader, - valueTupleType, - valueTupleConstructors, - columnBindings - ); + return rowDataReader => + MaterializeValueTuple(rowDataReader, valueTupleType, valueTupleConstructors, columnBindings); } /// @@ -314,16 +305,13 @@ Type[] dataReaderFieldTypes [UnconditionalSuppressMessage( "AOT", "IL3050:Requires dynamic code", - Justification = - "The call is inside an if (RuntimeFeature.IsDynamicCodeSupported) branch, which the AOT compiler folds " + - "to false and removes together with the expression-tree implementation. The net9.0+ analyzer " + - "recognizes that guard and reports nothing here; net8.0 lacks the [FeatureGuard] annotation on " + - "IsDynamicCodeSupported that lets it do so." + Justification = "The call is inside an if (RuntimeFeature.IsDynamicCodeSupported) branch, which the AOT compiler folds " + + "to false and removes together with the expression-tree implementation. The net9.0+ analyzer " + + "recognizes that guard and reports nothing here; net8.0 lacks the [FeatureGuard] annotation on " + + "IsDynamicCodeSupported that lets it do so." )] #endif - private static Delegate CreateMaterializer< - [DynamicallyAccessedMembers(ValueTupleMemberTypes)] TValueTuple - >( + private static Delegate CreateMaterializer<[DynamicallyAccessedMembers(ValueTupleMemberTypes)] TValueTuple>( Type[] valueTupleFieldTypes, DbDataReader dataReader, string[] dataReaderFieldNames, @@ -374,12 +362,7 @@ Type[] dataReaderFieldTypes [RequiresDynamicCode(MaterializerRequiresDynamicCodeMessage)] private static Delegate CreateExpressionMaterializer< [DynamicallyAccessedMembers(ValueTupleMemberTypes)] TValueTuple - >( - Type[] valueTupleFieldTypes, - DbDataReader dataReader, - string[] dataReaderFieldNames, - Type[] dataReaderFieldTypes - ) + >(Type[] valueTupleFieldTypes, DbDataReader dataReader, string[] dataReaderFieldNames, Type[] dataReaderFieldTypes) { var valueTupleType = typeof(TValueTuple); @@ -454,9 +437,9 @@ Type[] dataReaderFieldTypes Expression.New( typeof(InvalidCastException).GetConstructor([typeof(string)])!, Expression.Constant( - $"The {columnNameOrPosition} returned by the SQL statement contains a NULL " + - $"value, but the corresponding field of the value tuple type {valueTupleType} " + - "is non-nullable." + $"The {columnNameOrPosition} returned by the SQL statement contains a NULL " + + $"value, but the corresponding field of the value tuple type {valueTupleType} " + + "is non-nullable." ) ), targetType @@ -464,14 +447,12 @@ Type[] dataReaderFieldTypes var throwInvalidCastExceptionExpression = Expression.Throw( Expression.New( - typeof(InvalidCastException).GetConstructor( - [typeof(string), typeof(Exception)] - )!, + typeof(InvalidCastException).GetConstructor([typeof(string), typeof(Exception)])!, Expression.Constant( - $"The {columnNameOrPosition} returned by the SQL statement contains a " + - $"value that could not be converted to the type {targetType} " + - $"of the corresponding field of the value tuple type {valueTupleType}. " + - "See inner exception for details." + $"The {columnNameOrPosition} returned by the SQL statement contains a " + + $"value that could not be converted to the type {targetType} " + + $"of the corresponding field of the value tuple type {valueTupleType}. " + + "See inner exception for details." ), exceptionParameterExpression ), @@ -487,26 +468,21 @@ Type[] dataReaderFieldTypes ), targetType ), - Expression.Catch( - exceptionParameterExpression, - throwInvalidCastExceptionExpression - ) + Expression.Catch(exceptionParameterExpression, throwInvalidCastExceptionExpression) ); - var isNotDbNullBranchExpression = dataReaderFieldType != targetType - ? convertFieldValueExpression - : getFieldValueCallExpression; + var isNotDbNullBranchExpression = + dataReaderFieldType != targetType ? convertFieldValueExpression : getFieldValueCallExpression; - dataReaderFieldValueExpressions[fieldOrdinal] = - Expression.Condition( - Expression.Call( - dataReaderParameterExpression, - MaterializerFactoryHelper.DbDataReaderIsDBNullMethod, - fieldOrdinalExpression - ), - isDbNullBranchExpression, - isNotDbNullBranchExpression - ); + dataReaderFieldValueExpressions[fieldOrdinal] = Expression.Condition( + Expression.Call( + dataReaderParameterExpression, + MaterializerFactoryHelper.DbDataReaderIsDBNullMethod, + fieldOrdinalExpression + ), + isDbNullBranchExpression, + isNotDbNullBranchExpression + ); } // In C# value tuples with more than 7 fields are represented as nested value tuples. @@ -516,8 +492,9 @@ Type[] dataReaderFieldTypes // First we chunk the field value expressions into groups of 7. // We use a stack to reverse the order, so we start with the expressions for the most inner value tuple. - var fieldValueExpressionChunks = - new Stack(dataReaderFieldValueExpressions.Chunk(ValueTupleFieldCountBeforeNesting)); + var fieldValueExpressionChunks = new Stack( + dataReaderFieldValueExpressions.Chunk(ValueTupleFieldCountBeforeNesting) + ); // Then we get the constructors for the value tuple types, which GetValueTupleConstructors returns from the // outermost to the innermost. Pushing them onto a stack in that order reverses it, so we start with the @@ -542,10 +519,7 @@ Type[] dataReaderFieldTypes // the "Rest" parameter. var arguments = newExpression is not null ? [.. chunk, newExpression] : chunk; - newExpression = Expression.New( - constructor, - arguments - ); + newExpression = Expression.New(constructor, arguments); } return Expression.Lambda(newExpression!, dataReaderParameterExpression).Compile(); @@ -612,13 +586,13 @@ private static string GetColumnNameOrPosition(int fieldOrdinal, string? dataRead [UnconditionalSuppressMessage( "Trimming", "IL2065:Value passed to implicit 'this' parameter cannot be statically determined", - Justification = - "The nested value tuple types this walks are System.ValueTuple`1-`8, whose constructors the embedded " + - "ILLink.Descriptors.xml preserves in a consumer's trimmed or Native AOT publish. The caller has already " + - "rejected any type that is not a value tuple, and a unit test guards the descriptor's completeness." + Justification = "The nested value tuple types this walks are System.ValueTuple`1-`8, whose constructors the embedded " + + "ILLink.Descriptors.xml preserves in a consumer's trimmed or Native AOT publish. The caller has already " + + "rejected any type that is not a value tuple, and a unit test guards the descriptor's completeness." )] private static ConstructorInfo[] GetValueTupleConstructors( - [DynamicallyAccessedMembers(ValueTupleMemberTypes)] Type valueTupleType) + [DynamicallyAccessedMembers(ValueTupleMemberTypes)] Type valueTupleType + ) { var valueTupleConstructors = new List(); @@ -630,10 +604,7 @@ private static ConstructorInfo[] GetValueTupleConstructors( var genericArguments = currentValueTupleType.GetGenericArguments(); valueTupleConstructors.Add( - currentValueTupleType.GetConstructor( - BindingFlags.Public | BindingFlags.Instance, - genericArguments - )! + currentValueTupleType.GetConstructor(BindingFlags.Public | BindingFlags.Instance, genericArguments)! ); // Fewer than eight arguments means there is no "Rest" field, so this is the innermost value tuple type. @@ -804,9 +775,9 @@ ReflectionColumnBinding columnBinding } throw new InvalidCastException( - $"The {columnBinding.ColumnNameOrPosition} returned by the SQL statement contains a NULL " + - $"value, but the corresponding field of the value tuple type {valueTupleType} " + - "is non-nullable." + $"The {columnBinding.ColumnNameOrPosition} returned by the SQL statement contains a NULL " + + $"value, but the corresponding field of the value tuple type {valueTupleType} " + + "is non-nullable." ); } @@ -824,10 +795,10 @@ ReflectionColumnBinding columnBinding catch (Exception exception) { throw new InvalidCastException( - $"The {columnBinding.ColumnNameOrPosition} returned by the SQL statement contains a " + - $"value that could not be converted to the type {columnBinding.TargetType} " + - $"of the corresponding field of the value tuple type {valueTupleType}. " + - "See inner exception for details.", + $"The {columnBinding.ColumnNameOrPosition} returned by the SQL statement contains a " + + $"value that could not be converted to the type {columnBinding.TargetType} " + + $"of the corresponding field of the value tuple type {valueTupleType}. " + + "See inner exception for details.", exception ); } @@ -850,7 +821,8 @@ ReflectionColumnBinding columnBinding /// including the fields of all nested value tuple types. /// private static Type[] GetValueTupleFieldTypes( - [DynamicallyAccessedMembers(ValueTupleMemberTypes)] Type valueTupleType) + [DynamicallyAccessedMembers(ValueTupleMemberTypes)] Type valueTupleType + ) { var fieldTypes = new List(); var currentValueTupleType = valueTupleType; @@ -936,9 +908,9 @@ Type[] dataReaderFieldTypes if (dataReader.FieldCount != valueTupleFieldTypes.Length) { throw new ArgumentException( - $"The SQL statement returned {"column".ToQuantity(dataReader.FieldCount)}, but the value tuple type " + - $"{valueTupleType} has {"field".ToQuantity(valueTupleFieldTypes.Length)}. Make sure that the SQL " + - "statement returns the same number of columns as the number of fields in the value tuple type.", + $"The SQL statement returned {"column".ToQuantity(dataReader.FieldCount)}, but the value tuple type " + + $"{valueTupleType} has {"field".ToQuantity(valueTupleFieldTypes.Length)}. Make sure that the SQL " + + "statement returns the same number of columns as the number of fields in the value tuple type.", nameof(dataReader) ); } @@ -955,9 +927,9 @@ Type[] dataReaderFieldTypes if (!ValueConverter.CanConvert(dataReaderFieldType, valueTupleFieldType)) { throw new ArgumentException( - $"The data type {dataReaderFieldType} of the {columnNameOrPosition} returned by the SQL " + - $"statement is not compatible with the field type {valueTupleFieldType} of the corresponding " + - $"field of the value tuple type {valueTupleType}.", + $"The data type {dataReaderFieldType} of the {columnNameOrPosition} returned by the SQL " + + $"statement is not compatible with the field type {valueTupleFieldType} of the corresponding " + + $"field of the value tuple type {valueTupleType}.", nameof(dataReader) ); } @@ -965,8 +937,8 @@ Type[] dataReaderFieldTypes if (!MaterializerFactoryHelper.IsDbDataReaderTypedGetMethodAvailable(dataReaderFieldType)) { throw new ArgumentException( - $"The data type {dataReaderFieldType} of the {columnNameOrPosition} returned by the SQL " + - "statement is not supported.", + $"The data type {dataReaderFieldType} of the {columnNameOrPosition} returned by the SQL " + + "statement is not supported.", nameof(dataReader) ); } @@ -991,25 +963,22 @@ private readonly struct MaterializerCacheKey( Type[] valueTupleFieldTypes, string[] dataReaderFieldNames, Type[] dataReaderFieldTypes - ) - : IEquatable + ) : IEquatable { /// public bool Equals(MaterializerCacheKey other) => - this.ValueTupleFieldTypes.SequenceEqual(other.ValueTupleFieldTypes) && - this.DataReaderFieldNames.SequenceEqual(other.DataReaderFieldNames) && - this.DataReaderFieldTypes.SequenceEqual(other.DataReaderFieldTypes); + this.ValueTupleFieldTypes.SequenceEqual(other.ValueTupleFieldTypes) + && this.DataReaderFieldNames.SequenceEqual(other.DataReaderFieldNames) + && this.DataReaderFieldTypes.SequenceEqual(other.DataReaderFieldTypes); /// - public override bool Equals(object? obj) => - obj is MaterializerCacheKey other && this.Equals(other); + public override bool Equals(object? obj) => obj is MaterializerCacheKey other && this.Equals(other); /// public override int GetHashCode() { var hashCode = new HashCode(); - foreach (var fieldType in this.ValueTupleFieldTypes) { hashCode.Add(fieldType); diff --git a/src/DbConnectionPlus/Readers/CommandDisposingDataReaderDecorator.cs b/src/DbConnectionPlus/Readers/CommandDisposingDataReaderDecorator.cs index 2a72798..7902295 100644 --- a/src/DbConnectionPlus/Readers/CommandDisposingDataReaderDecorator.cs +++ b/src/DbConnectionPlus/Readers/CommandDisposingDataReaderDecorator.cs @@ -82,12 +82,10 @@ CancellationToken commandCancellationToken public override int VisibleFieldCount => this.dataReader.VisibleFieldCount; /// - public override void Close() => - this.dataReader.Close(); + public override void Close() => this.dataReader.Close(); /// - public override Task CloseAsync() => - this.dataReader.CloseAsync(); + public override Task CloseAsync() => this.dataReader.CloseAsync(); /// public override async ValueTask DisposeAsync() @@ -105,158 +103,120 @@ public override async ValueTask DisposeAsync() } /// - public override bool GetBoolean(int ordinal) => - this.dataReader.GetBoolean(ordinal); + public override bool GetBoolean(int ordinal) => this.dataReader.GetBoolean(ordinal); /// - public override byte GetByte(int ordinal) => - this.dataReader.GetByte(ordinal); + public override byte GetByte(int ordinal) => this.dataReader.GetByte(ordinal); /// - public override long GetBytes( - int ordinal, - long dataOffset, - byte[]? buffer, - int bufferOffset, - int length - ) => + public override long GetBytes(int ordinal, long dataOffset, byte[]? buffer, int bufferOffset, int length) => this.dataReader.GetBytes(ordinal, dataOffset, buffer, bufferOffset, length); /// - public override char GetChar(int ordinal) => - this.dataReader.GetChar(ordinal); + public override char GetChar(int ordinal) => this.dataReader.GetChar(ordinal); /// - public override long GetChars( - int ordinal, - long dataOffset, - char[]? buffer, - int bufferOffset, - int length - ) => + public override long GetChars(int ordinal, long dataOffset, char[]? buffer, int bufferOffset, int length) => this.dataReader.GetChars(ordinal, dataOffset, buffer, bufferOffset, length); /// public override Task> GetColumnSchemaAsync( CancellationToken cancellationToken = default - ) => - this.dataReader.GetColumnSchemaAsync(cancellationToken); + ) => this.dataReader.GetColumnSchemaAsync(cancellationToken); /// - public override string GetDataTypeName(int ordinal) => - this.dataReader.GetDataTypeName(ordinal); + public override string GetDataTypeName(int ordinal) => this.dataReader.GetDataTypeName(ordinal); /// - public override DateTime GetDateTime(int ordinal) => - this.dataReader.GetDateTime(ordinal); + public override DateTime GetDateTime(int ordinal) => this.dataReader.GetDateTime(ordinal); /// - public override decimal GetDecimal(int ordinal) => - this.dataReader.GetDecimal(ordinal); + public override decimal GetDecimal(int ordinal) => this.dataReader.GetDecimal(ordinal); /// - public override double GetDouble(int ordinal) => - this.dataReader.GetDouble(ordinal); + public override double GetDouble(int ordinal) => this.dataReader.GetDouble(ordinal); /// - public override IEnumerator GetEnumerator() => - this.dataReader.GetEnumerator(); + public override IEnumerator GetEnumerator() => this.dataReader.GetEnumerator(); /// [return: DynamicallyAccessedMembers( - DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] - public override Type GetFieldType(int ordinal) => - this.dataReader.GetFieldType(ordinal); + DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties + )] + public override Type GetFieldType(int ordinal) => this.dataReader.GetFieldType(ordinal); /// - public override T GetFieldValue(int ordinal) => - this.dataReader.GetFieldValue(ordinal); + public override T GetFieldValue(int ordinal) => this.dataReader.GetFieldValue(ordinal); /// public override Task GetFieldValueAsync(int ordinal, CancellationToken cancellationToken) => this.dataReader.GetFieldValueAsync(ordinal, cancellationToken); /// - public override float GetFloat(int ordinal) => - this.dataReader.GetFloat(ordinal); + public override float GetFloat(int ordinal) => this.dataReader.GetFloat(ordinal); /// - public override Guid GetGuid(int ordinal) => - this.dataReader.GetGuid(ordinal); + public override Guid GetGuid(int ordinal) => this.dataReader.GetGuid(ordinal); /// - public override short GetInt16(int ordinal) => - this.dataReader.GetInt16(ordinal); + public override short GetInt16(int ordinal) => this.dataReader.GetInt16(ordinal); /// - public override int GetInt32(int ordinal) => - this.dataReader.GetInt32(ordinal); + public override int GetInt32(int ordinal) => this.dataReader.GetInt32(ordinal); /// - public override long GetInt64(int ordinal) => - this.dataReader.GetInt64(ordinal); + public override long GetInt64(int ordinal) => this.dataReader.GetInt64(ordinal); /// - public override string GetName(int ordinal) => - this.dataReader.GetName(ordinal); + public override string GetName(int ordinal) => this.dataReader.GetName(ordinal); /// - public override int GetOrdinal(string name) => - this.dataReader.GetOrdinal(name); + public override int GetOrdinal(string name) => this.dataReader.GetOrdinal(name); /// [return: DynamicallyAccessedMembers( - DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] + DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties + )] public override Type GetProviderSpecificFieldType(int ordinal) => this.dataReader.GetProviderSpecificFieldType(ordinal); /// - public override object GetProviderSpecificValue(int ordinal) => - this.dataReader.GetProviderSpecificValue(ordinal); + public override object GetProviderSpecificValue(int ordinal) => this.dataReader.GetProviderSpecificValue(ordinal); /// - public override int GetProviderSpecificValues(object[] values) => - this.dataReader.GetProviderSpecificValues(values); + public override int GetProviderSpecificValues(object[] values) => this.dataReader.GetProviderSpecificValues(values); /// - public override DataTable? GetSchemaTable() => - this.dataReader.GetSchemaTable(); + public override DataTable? GetSchemaTable() => this.dataReader.GetSchemaTable(); /// public override Task GetSchemaTableAsync(CancellationToken cancellationToken = default) => this.dataReader.GetSchemaTableAsync(cancellationToken); /// - public override Stream GetStream(int ordinal) => - this.dataReader.GetStream(ordinal); + public override Stream GetStream(int ordinal) => this.dataReader.GetStream(ordinal); /// - public override string GetString(int ordinal) => - this.dataReader.GetString(ordinal); + public override string GetString(int ordinal) => this.dataReader.GetString(ordinal); /// - public override TextReader GetTextReader(int ordinal) => - this.dataReader.GetTextReader(ordinal); + public override TextReader GetTextReader(int ordinal) => this.dataReader.GetTextReader(ordinal); /// - public override object GetValue(int ordinal) => - this.dataReader.GetValue(ordinal); + public override object GetValue(int ordinal) => this.dataReader.GetValue(ordinal); /// - public override int GetValues(object[] values) => - this.dataReader.GetValues(values); + public override int GetValues(object[] values) => this.dataReader.GetValues(values); /// - public override bool IsDBNull(int ordinal) => - this.dataReader.IsDBNull(ordinal); + public override bool IsDBNull(int ordinal) => this.dataReader.IsDBNull(ordinal); /// public override Task IsDBNullAsync(int ordinal, CancellationToken cancellationToken) => this.dataReader.IsDBNullAsync(ordinal, cancellationToken); /// - public override bool NextResult() => - this.dataReader.NextResult(); + public override bool NextResult() => this.dataReader.NextResult(); /// public override Task NextResultAsync(CancellationToken cancellationToken) => @@ -273,8 +233,7 @@ public override bool Read() return this.dataReader.Read(); } catch (Exception exception) - when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( exception, this.commandCancellationToken ) @@ -295,19 +254,12 @@ public override async Task ReadAsync(CancellationToken cancellationToken) return await this.dataReader.ReadAsync(cancellationToken).ConfigureAwait(false); } catch (Exception exception) - when ( - this.databaseAdapter - .WasSqlStatementCancelledByCancellationToken( - exception, - cancellationToken - ) - ) + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken)) { throw new OperationCanceledException(cancellationToken); } catch (Exception exception) - when ( - this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( + when (this.databaseAdapter.WasSqlStatementCancelledByCancellationToken( exception, this.commandCancellationToken ) @@ -318,8 +270,7 @@ public override async Task ReadAsync(CancellationToken cancellationToken) } /// - public override string? ToString() => - this.dataReader.ToString(); + public override string? ToString() => this.dataReader.ToString(); /// protected override void Dispose(bool disposing) diff --git a/src/DbConnectionPlus/Readers/EnumerableReader.cs b/src/DbConnectionPlus/Readers/EnumerableReader.cs index dcd2039..43c95bf 100644 --- a/src/DbConnectionPlus/Readers/EnumerableReader.cs +++ b/src/DbConnectionPlus/Readers/EnumerableReader.cs @@ -55,9 +55,11 @@ internal sealed class EnumerableReader : DbDataReader public EnumerableReader( IEnumerable values, [DynamicallyAccessedMembers( - DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] - Type valuesType, - string fieldName) + DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties + )] + Type valuesType, + string fieldName + ) { ArgumentNullException.ThrowIfNull(values); ArgumentNullException.ThrowIfNull(valuesType); @@ -104,7 +106,8 @@ public EnumerableReader( public EnumerableReader( IEnumerable values, IReadOnlyList properties, - EnumerableReaderOptions options) + EnumerableReaderOptions options + ) { ArgumentNullException.ThrowIfNull(values); ArgumentNullException.ThrowIfNull(properties); @@ -169,61 +172,41 @@ public override void Close() } /// - public override bool GetBoolean(int ordinal) => - (bool)this.GetValue(ordinal); + public override bool GetBoolean(int ordinal) => (bool)this.GetValue(ordinal); /// - public override byte GetByte(int ordinal) => - (byte)this.GetValue(ordinal); + public override byte GetByte(int ordinal) => (byte)this.GetValue(ordinal); /// /// Always thrown. - public override long GetBytes( - int ordinal, - long dataOffset, - byte[]? buffer, - int bufferOffset, - int length - ) => + public override long GetBytes(int ordinal, long dataOffset, byte[]? buffer, int bufferOffset, int length) => throw new NotImplementedException(); /// - public override char GetChar(int ordinal) => - (char)this.GetValue(ordinal); + public override char GetChar(int ordinal) => (char)this.GetValue(ordinal); /// /// Always thrown. - public override long GetChars( - int ordinal, - long dataOffset, - char[]? buffer, - int bufferOffset, - int length - ) => + public override long GetChars(int ordinal, long dataOffset, char[]? buffer, int bufferOffset, int length) => throw new NotImplementedException(); /// /// /// The specified ordinal is not one of the ordinals the reader supports. /// - public override string GetDataTypeName(int ordinal) => - this.GetFieldType(ordinal).Name; + public override string GetDataTypeName(int ordinal) => this.GetFieldType(ordinal).Name; /// - public override DateTime GetDateTime(int ordinal) => - (DateTime)this.GetValue(ordinal); + public override DateTime GetDateTime(int ordinal) => (DateTime)this.GetValue(ordinal); /// - public override decimal GetDecimal(int ordinal) => - (decimal)this.GetValue(ordinal); + public override decimal GetDecimal(int ordinal) => (decimal)this.GetValue(ordinal); /// - public override double GetDouble(int ordinal) => - (double)this.GetValue(ordinal); + public override double GetDouble(int ordinal) => (double)this.GetValue(ordinal); /// - public override IEnumerator GetEnumerator() => - this.enumerator; + public override IEnumerator GetEnumerator() => this.enumerator; /// /// @@ -239,7 +222,8 @@ public override IEnumerator GetEnumerator() => /// contract by construction. /// [return: DynamicallyAccessedMembers( - DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] + DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties + )] public override Type GetFieldType(int ordinal) { this.EnsureValidFieldOrdinal(ordinal); @@ -248,16 +232,13 @@ public override Type GetFieldType(int ordinal) } /// - public override float GetFloat(int ordinal) => - (float)this.GetValue(ordinal); + public override float GetFloat(int ordinal) => (float)this.GetValue(ordinal); /// - public override Guid GetGuid(int ordinal) => - (Guid)this.GetValue(ordinal); + public override Guid GetGuid(int ordinal) => (Guid)this.GetValue(ordinal); /// - public override short GetInt16(int ordinal) => - (short)this.GetValue(ordinal); + public override short GetInt16(int ordinal) => (short)this.GetValue(ordinal); /// public override int GetInt32(int ordinal) @@ -273,8 +254,7 @@ public override int GetInt32(int ordinal) } /// - public override long GetInt64(int ordinal) => - (long)this.GetValue(ordinal); + public override long GetInt64(int ordinal) => (long)this.GetValue(ordinal); /// /// @@ -297,9 +277,7 @@ public override string GetName(int ordinal) /// bulk-copy APIs of the database providers expect - they probe for columns they may not find. /// public override int GetOrdinal(string name) => - this.IsSingleColumn - ? this.GetOrdinalOrThrow(name) - : Array.IndexOf(this.fieldNames, name); + this.IsSingleColumn ? this.GetOrdinalOrThrow(name) : Array.IndexOf(this.fieldNames, name); /// /// Always thrown. @@ -310,8 +288,7 @@ public override int GetOrdinal(string name) => /// this project does not suppress. Nothing asks for it either: the bulk-copy APIs of all five providers drive /// this reader through , and . /// - public override DataTable GetSchemaTable() => - throw new NotImplementedException(); + public override DataTable GetSchemaTable() => throw new NotImplementedException(); /// public override string GetString(int ordinal) @@ -392,8 +369,7 @@ public override int GetValues(object[] values) /// /// The specified ordinal is not one of the ordinals the reader supports. /// - public override bool IsDBNull(int ordinal) => - this.GetValue(ordinal) is DBNull; + public override bool IsDBNull(int ordinal) => this.GetValue(ordinal) is DBNull; /// public override bool NextResult() => false; @@ -442,14 +418,12 @@ protected override void Dispose(bool disposing) /// /// Gets a value indicating whether the reader returns values as . /// - private bool ReadsCharsAsStrings => - this.options.HasFlag(EnumerableReaderOptions.ReadCharsAsStrings); + private bool ReadsCharsAsStrings => this.options.HasFlag(EnumerableReaderOptions.ReadCharsAsStrings); /// /// Gets a value indicating whether the reader serializes values while reading them. /// - private bool SerializesEnums => - this.options.HasFlag(EnumerableReaderOptions.SerializeEnums); + private bool SerializesEnums => this.options.HasFlag(EnumerableReaderOptions.SerializeEnums); /// /// Disposes the enumerator obtained from the enumerable. @@ -484,8 +458,8 @@ private void EnsureValidFieldOrdinal(int ordinal) ordinal, this.IsSingleColumn ? $"The specified ordinal {ordinal} is not supported. The only supported ordinal is zero." - : $"The specified ordinal {ordinal} is not supported. The supported ordinals are 0 to " + - $"{this.FieldCount - 1}." + : $"The specified ordinal {ordinal} is not supported. The supported ordinals are 0 to " + + $"{this.FieldCount - 1}." ); } @@ -497,8 +471,7 @@ private void EnsureValidFieldOrdinal(int ordinal) /// The type passed to the constructor if the reader reads a single column; otherwise the type of the property /// the column is mapped to. /// - private Type GetColumnType(int ordinal) => - this.valuesType ?? this.properties[ordinal].PropertyType; + private Type GetColumnType(int ordinal) => this.valuesType ?? this.properties[ordinal].PropertyType; /// /// Resolves the ordinal of the specified field name, throwing when the reader does not have such a field. @@ -520,10 +493,10 @@ private int GetOrdinalOrThrow(string name) throw new ArgumentOutOfRangeException( nameof(name), this.IsSingleColumn - ? $"The specified field name '{name}' is not supported. The only supported field name is " + - $"'{this.fieldNames[0]}'." - : $"The specified field name '{name}' is not supported. The supported field names are " + - $"'{string.Join("', '", this.fieldNames)}'." + ? $"The specified field name '{name}' is not supported. The only supported field name is " + + $"'{this.fieldNames[0]}'." + : $"The specified field name '{name}' is not supported. The supported field names are " + + $"'{string.Join("', '", this.fieldNames)}'." ); } @@ -535,8 +508,7 @@ private int GetOrdinalOrThrow(string name) /// if the column is mapped to an property; otherwise, /// . /// - private bool IsEnumColumn(int ordinal) => - this.GetColumnType(ordinal).IsEnumOrNullableEnumType(); + private bool IsEnumColumn(int ordinal) => this.GetColumnType(ordinal).IsEnumOrNullableEnumType(); /// /// Applies the reader's to a value that was read from an entity. @@ -584,7 +556,8 @@ private object SerializeValue(object value) /// field types, derives its NpgsqlDbType values from the entity metadata instead. /// [return: DynamicallyAccessedMembers( - DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] + DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties + )] private static Type MapReportedFieldType(Type propertyType, EnumerableReaderOptions options) { if (propertyType.IsEnumOrNullableEnumType()) @@ -598,13 +571,11 @@ private static Type MapReportedFieldType(Type propertyType, EnumerableReaderOpti return enumSerializationMode switch { - EnumSerializationMode.Strings => - typeof(string), + EnumSerializationMode.Strings => typeof(string), - EnumSerializationMode.Integers => - typeof(int), + EnumSerializationMode.Integers => typeof(int), - _ => ThrowInvalidEnumSerializationModeException(enumSerializationMode) + _ => ThrowInvalidEnumSerializationModeException(enumSerializationMode), }; } @@ -628,7 +599,8 @@ private static Type MapReportedFieldType(Type propertyType, EnumerableReaderOpti /// Always thrown. [DoesNotReturn] [return: DynamicallyAccessedMembers( - DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] + DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties + )] private static Type ThrowInvalidEnumSerializationModeException(EnumSerializationMode enumSerializationMode) => throw new ArgumentOutOfRangeException( nameof(enumSerializationMode), @@ -650,7 +622,8 @@ private static Type ThrowInvalidEnumSerializationModeException(EnumSerialization /// annotation, so the trimmer reports IL2073 for it. Only a typeof literal satisfies the contract. /// [return: DynamicallyAccessedMembers( - DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] + DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties + )] private static Type MapBuiltInFieldType(Type propertyType) { if (propertyType == typeof(bool)) @@ -775,8 +748,10 @@ private static Type MapBuiltInFieldType(Type propertyType) private readonly string[] fieldNames; private readonly EnumerableReaderOptions options; private readonly EntityPropertyMetadata[] properties; + [DynamicallyAccessedMembers( - DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] + DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties + )] private readonly Type? valuesType; private object? current; private bool isClosed; diff --git a/src/DbConnectionPlus/Readers/EnumerableReaderOptions.cs b/src/DbConnectionPlus/Readers/EnumerableReaderOptions.cs index 9a2e831..db755d3 100644 --- a/src/DbConnectionPlus/Readers/EnumerableReaderOptions.cs +++ b/src/DbConnectionPlus/Readers/EnumerableReaderOptions.cs @@ -30,5 +30,5 @@ internal enum EnumerableReaderOptions /// Report columns as and return their values as /// , mirroring what the data readers of the major database systems do for CHAR columns. /// - ReadCharsAsStrings = 2 + ReadCharsAsStrings = 2, } diff --git a/src/DbConnectionPlus/SqlStatements/InterpolatedParameter.cs b/src/DbConnectionPlus/SqlStatements/InterpolatedParameter.cs index bb6f71c..b1f10c3 100644 --- a/src/DbConnectionPlus/SqlStatements/InterpolatedParameter.cs +++ b/src/DbConnectionPlus/SqlStatements/InterpolatedParameter.cs @@ -11,5 +11,4 @@ namespace RentADeveloper.DbConnectionPlus.SqlStatements; /// This is if no name could be inferred. /// /// The value of the parameter. -public record InterpolatedParameter(string? InferredName, object? Value) - : IInterpolatedSqlStatementFragment; +public record InterpolatedParameter(string? InferredName, object? Value) : IInterpolatedSqlStatementFragment; diff --git a/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatement.cs b/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatement.cs index 2fa5730..52fe83b 100644 --- a/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatement.cs +++ b/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatement.cs @@ -71,7 +71,10 @@ public InterpolatedSqlStatement(string code, params (string Name, object? Value) ArgumentNullException.ThrowIfNull(code); ArgumentNullException.ThrowIfNull(parameters); - this.fragments = new(1 /* fragment for the code */ + parameters.Length /* fragments for the parameters */); + this.fragments = new( + 1 /* fragment for the code */ + + parameters.Length /* fragments for the parameters */ + ); this.temporaryTables = []; this.fragments.Add(new Literal(code)); @@ -86,8 +89,8 @@ public InterpolatedSqlStatement(string code, params (string Name, object? Value) var duplicateParameterNames = duplicateParameters.SelectMany(a => a.Select(b => $"'{b.Name}'")).ToList(); throw new ArgumentException( - "The specified parameters have the following duplicate parameter names: " + - $"{string.Join(", ", duplicateParameterNames)}. Make sure each parameter name is only used once.", + "The specified parameters have the following duplicate parameter names: " + + $"{string.Join(", ", duplicateParameterNames)}. Make sure each parameter name is only used once.", nameof(parameters) ); } @@ -128,14 +131,13 @@ public void AppendFormatted(T? value, int alignment = 0, string? format = nul break; default: - var formattedValue = - value switch - { - string stringValue => stringValue, - IFormattable formattable => formattable.ToString(format, CultureInfo.InvariantCulture), - null => string.Empty, - _ => value.ToString() ?? string.Empty - }; + var formattedValue = value switch + { + string stringValue => stringValue, + IFormattable formattable => formattable.ToString(format, CultureInfo.InvariantCulture), + null => string.Empty, + _ => value.ToString() ?? string.Empty, + }; if (alignment != 0) { @@ -182,15 +184,13 @@ public void AppendLiteral(string? value) } /// - public readonly bool Equals(InterpolatedSqlStatement other) => - this.fragments.SequenceEqual(other.Fragments); + public readonly bool Equals(InterpolatedSqlStatement other) => this.fragments.SequenceEqual(other.Fragments); /// - public readonly override bool Equals(object? obj) => - obj is InterpolatedSqlStatement other && this.Equals(other); + public override readonly bool Equals(object? obj) => obj is InterpolatedSqlStatement other && this.Equals(other); /// - public readonly override int GetHashCode() + public override readonly int GetHashCode() { var hashCode = new HashCode(); @@ -203,7 +203,7 @@ public readonly override int GetHashCode() } /// - public readonly override string ToString() + public override readonly string ToString() { using var stringBuilder = new ValueStringBuilder(stackalloc char[500]); @@ -320,8 +320,7 @@ public static InterpolatedSqlStatement FromString(string value) /// if the two specified instances of are /// equal; otherwise, . /// - public static bool operator ==(InterpolatedSqlStatement left, InterpolatedSqlStatement right) => - left.Equals(right); + public static bool operator ==(InterpolatedSqlStatement left, InterpolatedSqlStatement right) => left.Equals(right); /// /// Implicitly converts a string to an instance of . @@ -344,8 +343,7 @@ public static implicit operator InterpolatedSqlStatement(string value) /// if the two the specified instances of are /// unequal; otherwise, . /// - public static bool operator !=(InterpolatedSqlStatement left, InterpolatedSqlStatement right) => - !(left == right); + public static bool operator !=(InterpolatedSqlStatement left, InterpolatedSqlStatement right) => !(left == right); /// /// The fragments that make up this SQL statement. diff --git a/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatementDebugView.cs b/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatementDebugView.cs index 6b219ca..4002c3b 100644 --- a/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatementDebugView.cs +++ b/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatementDebugView.cs @@ -12,12 +12,10 @@ internal sealed class InterpolatedSqlStatementDebugView(InterpolatedSqlStatement /// /// The debug view of the SQL statement. /// - public string DebugView => - statement.ToString(); + public string DebugView => statement.ToString(); /// /// The fragments that make up the SQL statement. /// - public IReadOnlyList Fragments => - statement.Fragments; + public IReadOnlyList Fragments => statement.Fragments; } diff --git a/src/DbConnectionPlus/SqlStatements/InterpolatedTemporaryTable.cs b/src/DbConnectionPlus/SqlStatements/InterpolatedTemporaryTable.cs index f78f71a..892bd15 100644 --- a/src/DbConnectionPlus/SqlStatements/InterpolatedTemporaryTable.cs +++ b/src/DbConnectionPlus/SqlStatements/InterpolatedTemporaryTable.cs @@ -20,6 +20,5 @@ public record InterpolatedTemporaryTable( IEnumerable Values, [property: DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] [param: DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] - Type ValuesType -) - : IInterpolatedSqlStatementFragment; + Type ValuesType +) : IInterpolatedSqlStatementFragment; diff --git a/src/DbConnectionPlus/ThrowHelper.cs b/src/DbConnectionPlus/ThrowHelper.cs index c84b8b2..48d3aee 100644 --- a/src/DbConnectionPlus/ThrowHelper.cs +++ b/src/DbConnectionPlus/ThrowHelper.cs @@ -36,9 +36,9 @@ public static void ThrowConfigurationIsFrozenException() => public static void ThrowDatabaseAdapterDoesNotSupportTemporaryTablesException(IDatabaseAdapter databaseAdapter) => throw new NotSupportedException( #pragma warning disable CA1062 - $"The database adapter {databaseAdapter.GetType()} does not support (local / session-scoped) " + - "temporary tables. Therefore the temporary tables feature of DbConnectionPlus can not be used with " + - "this database." + $"The database adapter {databaseAdapter.GetType()} does not support (local / session-scoped) " + + "temporary tables. Therefore the temporary tables feature of DbConnectionPlus can not be used with " + + "this database." #pragma warning restore CA1062 ); @@ -60,10 +60,10 @@ public static void ThrowDatabaseOperationAffectedUnexpectedNumberOfRowsException object entity ) => throw new DbUpdateConcurrencyException( - $"The database operation was expected to affect {expectedNumberOfAffectedRows} row(s), but actually " + - $"affected {actualNumberOfAffectedRows} row(s). Data in the database may have been modified or deleted " + - $"since entities were loaded. See {nameof(DbUpdateConcurrencyException)}." + - $"{nameof(DbUpdateConcurrencyException.Entity)} for the entity that was involved in the operation.", + $"The database operation was expected to affect {expectedNumberOfAffectedRows} row(s), but actually " + + $"affected {actualNumberOfAffectedRows} row(s). Data in the database may have been modified or deleted " + + $"since entities were loaded. See {nameof(DbUpdateConcurrencyException)}." + + $"{nameof(DbUpdateConcurrencyException.Entity)} for the entity that was involved in the operation.", entity ); @@ -76,8 +76,8 @@ object entity [DoesNotReturn] public static void ThrowEntityTypeHasNoKeyPropertyException(Type entityType) => throw new ArgumentException( - $"No property of the type {entityType} is configured as a key property. Make sure that at least one " + - "instance property of that type is configured as key property." + $"No property of the type {entityType} is configured as a key property. Make sure that at least one " + + "instance property of that type is configured as key property." ); /// @@ -134,13 +134,12 @@ public static void ThrowSqlStatementReturnedNoRowsException() => [MethodImpl(MethodImplOptions.NoInlining)] [DoesNotReturn] public static T ThrowWrongConnectionTypeException() - where TExpectedConnectionType : DbConnection - => - throw new ArgumentOutOfRangeException( - // ReSharper disable once NotResolvedInText - "connection", - $"The provided connection is not of the type {typeof(TExpectedConnectionType)}." - ); + where TExpectedConnectionType : DbConnection => + throw new ArgumentOutOfRangeException( + // ReSharper disable once NotResolvedInText + "connection", + $"The provided connection is not of the type {typeof(TExpectedConnectionType)}." + ); /// /// Throws an indicating that the specified transaction is not of the @@ -156,11 +155,10 @@ public static T ThrowWrongConnectionTypeException() [MethodImpl(MethodImplOptions.NoInlining)] [DoesNotReturn] public static T ThrowWrongTransactionTypeException() - where TExpectedTransactionType : DbTransaction - => - throw new ArgumentOutOfRangeException( - // ReSharper disable once NotResolvedInText - "transaction", - $"The provided transaction is not of the type {typeof(TExpectedTransactionType)}." - ); + where TExpectedTransactionType : DbTransaction => + throw new ArgumentOutOfRangeException( + // ReSharper disable once NotResolvedInText + "transaction", + $"The provided transaction is not of the type {typeof(TExpectedTransactionType)}." + ); } diff --git a/tests/DbConnectionPlus.IntegrationTests/Assertions/EntityAssertions.cs b/tests/DbConnectionPlus.IntegrationTests/Assertions/EntityAssertions.cs index d3f854e..af40db0 100644 --- a/tests/DbConnectionPlus.IntegrationTests/Assertions/EntityAssertions.cs +++ b/tests/DbConnectionPlus.IntegrationTests/Assertions/EntityAssertions.cs @@ -12,64 +12,44 @@ public static class EntityAssertions /// /// The data row to assert. /// The entity to assert against. - public static void AssertDataRowMatchesEntity( - DataRow dataRow, - Entity entity - ) + public static void AssertDataRowMatchesEntity(DataRow dataRow, Entity entity) { // We need to use the ValueConverter here because each database provider handles the types a bit // differently. - ValueConverter.ConvertValueToType(dataRow["BooleanValue"]) - .Should().Be(entity.BooleanValue); + ValueConverter.ConvertValueToType(dataRow["BooleanValue"]).Should().Be(entity.BooleanValue); - ValueConverter.ConvertValueToType(dataRow["ByteValue"]) - .Should().Be(entity.ByteValue); + ValueConverter.ConvertValueToType(dataRow["ByteValue"]).Should().Be(entity.ByteValue); - ValueConverter.ConvertValueToType(dataRow["CharValue"]) - .Should().Be(entity.CharValue); + ValueConverter.ConvertValueToType(dataRow["CharValue"]).Should().Be(entity.CharValue); - ValueConverter.ConvertValueToType(dataRow["DateOnlyValue"]) - .Should().Be(entity.DateOnlyValue); + ValueConverter.ConvertValueToType(dataRow["DateOnlyValue"]).Should().Be(entity.DateOnlyValue); - ValueConverter.ConvertValueToType(dataRow["DateTimeValue"]) - .Should().Be(entity.DateTimeValue); + ValueConverter.ConvertValueToType(dataRow["DateTimeValue"]).Should().Be(entity.DateTimeValue); - ValueConverter.ConvertValueToType(dataRow["DecimalValue"]) - .Should().Be(entity.DecimalValue); + ValueConverter.ConvertValueToType(dataRow["DecimalValue"]).Should().Be(entity.DecimalValue); - ValueConverter.ConvertValueToType(dataRow["DoubleValue"]) - .Should().Be(entity.DoubleValue); + ValueConverter.ConvertValueToType(dataRow["DoubleValue"]).Should().Be(entity.DoubleValue); - ValueConverter.ConvertValueToType(dataRow["EnumValue"]) - .Should().Be(entity.EnumValue); + ValueConverter.ConvertValueToType(dataRow["EnumValue"]).Should().Be(entity.EnumValue); - ValueConverter.ConvertValueToType(dataRow["GuidValue"]) - .Should().Be(entity.GuidValue); + ValueConverter.ConvertValueToType(dataRow["GuidValue"]).Should().Be(entity.GuidValue); - ValueConverter.ConvertValueToType(dataRow["Id"]) - .Should().Be(entity.Id); + ValueConverter.ConvertValueToType(dataRow["Id"]).Should().Be(entity.Id); - ValueConverter.ConvertValueToType(dataRow["Int16Value"]) - .Should().Be(entity.Int16Value); + ValueConverter.ConvertValueToType(dataRow["Int16Value"]).Should().Be(entity.Int16Value); - ValueConverter.ConvertValueToType(dataRow["Int32Value"]) - .Should().Be(entity.Int32Value); + ValueConverter.ConvertValueToType(dataRow["Int32Value"]).Should().Be(entity.Int32Value); - ValueConverter.ConvertValueToType(dataRow["Int64Value"]) - .Should().Be(entity.Int64Value); + ValueConverter.ConvertValueToType(dataRow["Int64Value"]).Should().Be(entity.Int64Value); - ValueConverter.ConvertValueToType(dataRow["SingleValue"]) - .Should().Be(entity.SingleValue); + ValueConverter.ConvertValueToType(dataRow["SingleValue"]).Should().Be(entity.SingleValue); - ValueConverter.ConvertValueToType(dataRow["StringValue"]) - .Should().Be(entity.StringValue); + ValueConverter.ConvertValueToType(dataRow["StringValue"]).Should().Be(entity.StringValue); - ValueConverter.ConvertValueToType(dataRow["TimeOnlyValue"]) - .Should().Be(entity.TimeOnlyValue); + ValueConverter.ConvertValueToType(dataRow["TimeOnlyValue"]).Should().Be(entity.TimeOnlyValue); - ValueConverter.ConvertValueToType(dataRow["TimeSpanValue"]) - .Should().Be(entity.TimeSpanValue); + ValueConverter.ConvertValueToType(dataRow["TimeSpanValue"]).Should().Be(entity.TimeSpanValue); } /// @@ -77,10 +57,7 @@ Entity entity /// /// The list of data rows to assert. /// The list of entities to assert against. - public static void AssertDataRowsMatchEntities( - List dataRows, - List entities - ) + public static void AssertDataRowsMatchEntities(List dataRows, List entities) { for (var i = 0; i < entities.Count; i++) { diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntitiesTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntitiesTests.cs index 638ad22..bfb625f 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntitiesTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntitiesTests.cs @@ -4,40 +4,32 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.DatabaseAdapters; -public sealed class - EntityManipulator_DeleteEntitiesTests_MySql : - EntityManipulator_DeleteEntitiesTests; +public sealed class EntityManipulator_DeleteEntitiesTests_MySql + : EntityManipulator_DeleteEntitiesTests; -public sealed class - EntityManipulator_DeleteEntitiesTests_Oracle : - EntityManipulator_DeleteEntitiesTests; +public sealed class EntityManipulator_DeleteEntitiesTests_Oracle + : EntityManipulator_DeleteEntitiesTests; -public sealed class - EntityManipulator_DeleteEntitiesTests_PostgreSql : - EntityManipulator_DeleteEntitiesTests; +public sealed class EntityManipulator_DeleteEntitiesTests_PostgreSql + : EntityManipulator_DeleteEntitiesTests; -public sealed class - EntityManipulator_DeleteEntitiesTests_Sqlite : - EntityManipulator_DeleteEntitiesTests; +public sealed class EntityManipulator_DeleteEntitiesTests_Sqlite + : EntityManipulator_DeleteEntitiesTests; -public sealed class - EntityManipulator_DeleteEntitiesTests_SqlServer : - EntityManipulator_DeleteEntitiesTests; +public sealed class EntityManipulator_DeleteEntitiesTests_SqlServer + : EntityManipulator_DeleteEntitiesTests; -public abstract class EntityManipulator_DeleteEntitiesTests - : IntegrationTestsBase +public abstract class EntityManipulator_DeleteEntitiesTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { /// - protected EntityManipulator_DeleteEntitiesTests() => - this.manipulator = this.DatabaseAdapter.EntityManipulator; + protected EntityManipulator_DeleteEntitiesTests() => this.manipulator = this.DatabaseAdapter.EntityManipulator; [Theory] [InlineData(false)] [InlineData(true)] - public async Task DeleteEntities_CancellationToken_ShouldCancelOperationIfCancellationIsRequested( - bool useAsyncApi - ) + public async Task DeleteEntities_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -48,22 +40,15 @@ bool useAsyncApi this.DelayNextDbCommand = true; - await Invoking(() => this.CallApi( - useAsyncApi, - this.Connection, - entitiesToDelete, - null, - cancellationToken - ) - ) - .Should().ThrowAsync() + await Invoking(() => this.CallApi(useAsyncApi, this.Connection, entitiesToDelete, null, cancellationToken)) + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); foreach (var entity in entities) { // Since the operation was cancelled, all entities should still exist. - this.ExistsEntityInDb(entity) - .Should().BeTrue(); + this.ExistsEntityInDb(entity).Should().BeTrue(); } } @@ -77,7 +62,9 @@ public async Task DeleteEntities_ConcurrencyTokenMismatch_ShouldThrow(bool useAs var failingEntity = entitiesToDelete[^1]; failingEntity.ConcurrencyToken_ = Generate.Single(); - var exception = (await Invoking(() => this.CallApi( + var exception = ( + await Invoking(() => + this.CallApi( useAsyncApi, this.Connection, entitiesToDelete, @@ -85,28 +72,27 @@ public async Task DeleteEntities_ConcurrencyTokenMismatch_ShouldThrow(bool useAs TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync()) - .Subject.First(); - - exception.Message - .Should().Be( - "The database operation was expected to affect 1 row(s), but actually affected 0 row(s). " + - "Data in the database may have been modified or deleted since entities were loaded. See " + - $"{nameof(DbUpdateConcurrencyException)}.{nameof(DbUpdateConcurrencyException.Entity)} for " + - "the entity that was involved in the operation." + .Should() + .ThrowAsync() + ).Subject.First(); + + exception + .Message.Should() + .Be( + "The database operation was expected to affect 1 row(s), but actually affected 0 row(s). " + + "Data in the database may have been modified or deleted since entities were loaded. See " + + $"{nameof(DbUpdateConcurrencyException)}.{nameof(DbUpdateConcurrencyException.Entity)} for " + + "the entity that was involved in the operation." ); - exception.Entity - .Should().Be(failingEntity); + exception.Entity.Should().Be(failingEntity); foreach (var entity in entitiesToDelete.Except([failingEntity])) { - this.ExistsEntityInDb(entity) - .Should().BeFalse(); + this.ExistsEntityInDb(entity).Should().BeFalse(); } - this.ExistsEntityInDb(failingEntity) - .Should().BeTrue(); + this.ExistsEntityInDb(failingEntity).Should().BeTrue(); } [Theory] @@ -118,24 +104,16 @@ public async Task DeleteEntities_Mapping_Attributes_ShouldUseAttributesMapping(b var entitiesToDelete = entities.Take(5).ToList(); var entitiesToKeep = entities.Skip(5).ToList(); - await this.CallApi( - useAsyncApi, - this.Connection, - entitiesToDelete, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, entitiesToDelete, null, TestContext.Current.CancellationToken); foreach (var entity in entitiesToDelete) { - this.ExistsEntityInDb(entity) - .Should().BeFalse(); + this.ExistsEntityInDb(entity).Should().BeFalse(); } foreach (var entity in entitiesToKeep) { - this.ExistsEntityInDb(entity) - .Should().BeTrue(); + this.ExistsEntityInDb(entity).Should().BeTrue(); } } @@ -150,24 +128,16 @@ public async Task DeleteEntities_Mapping_FluentApi_ShouldUseFluentApiMapping(boo var entitiesToDelete = entities.Take(5).ToList(); var entitiesToKeep = entities.Skip(5).ToList(); - await this.CallApi( - useAsyncApi, - this.Connection, - entitiesToDelete, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, entitiesToDelete, null, TestContext.Current.CancellationToken); foreach (var entity in entitiesToDelete) { - this.ExistsEntityInDb(entity) - .Should().BeFalse(); + this.ExistsEntityInDb(entity).Should().BeFalse(); } foreach (var entity in entitiesToKeep) { - this.ExistsEntityInDb(entity) - .Should().BeTrue(); + this.ExistsEntityInDb(entity).Should().BeTrue(); } } @@ -178,7 +148,8 @@ public Task DeleteEntities_Mapping_MissingKeyProperty_ShouldThrow(bool useAsyncA { var entityWithoutKeyProperty = new EntityWithoutKeyProperty(); - return Invoking(() => this.CallApi( + return Invoking(() => + this.CallApi( useAsyncApi, this.Connection, [entityWithoutKeyProperty], @@ -186,10 +157,11 @@ public Task DeleteEntities_Mapping_MissingKeyProperty_ShouldThrow(bool useAsyncA TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"No property of the type {typeof(EntityWithoutKeyProperty)} is configured as a key property. Make " + - "sure that at least one instance property of that type is configured as key property." + $"No property of the type {typeof(EntityWithoutKeyProperty)} is configured as a key property. Make " + + "sure that at least one instance property of that type is configured as key property." ); } @@ -202,24 +174,16 @@ public async Task DeleteEntities_Mapping_NoMapping_ShouldUseEntityTypeNameAndPro var entitiesToDelete = entities.Take(5).ToList(); var entitiesToKeep = entities.Skip(5).ToList(); - await this.CallApi( - useAsyncApi, - this.Connection, - entitiesToDelete, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, entitiesToDelete, null, TestContext.Current.CancellationToken); foreach (var entity in entitiesToDelete) { - this.ExistsEntityInDb(entity) - .Should().BeFalse(); + this.ExistsEntityInDb(entity).Should().BeFalse(); } foreach (var entity in entitiesToKeep) { - this.ExistsEntityInDb(entity) - .Should().BeTrue(); + this.ExistsEntityInDb(entity).Should().BeTrue(); } } @@ -233,35 +197,37 @@ public async Task DeleteEntities_RowVersionMismatch_ShouldThrow(bool useAsyncApi var failingEntity = entitiesToDelete[^1]; failingEntity.RowVersion_ = Generate.Single(); - var exception = (await Invoking(() => this.CallApi( - useAsyncApi, - this.Connection, - entitiesToDelete, - null, - TestContext.Current.CancellationToken + var exception = ( + await Invoking(() => + this.CallApi( + useAsyncApi, + this.Connection, + entitiesToDelete, + null, + TestContext.Current.CancellationToken + ) ) - ) - .Should().ThrowAsync()).Subject.First(); - - exception.Message - .Should().Be( - "The database operation was expected to affect 1 row(s), but actually affected 0 row(s). " + - "Data in the database may have been modified or deleted since entities were loaded. See " + - $"{nameof(DbUpdateConcurrencyException)}.{nameof(DbUpdateConcurrencyException.Entity)} for " + - "the entity that was involved in the operation." + .Should() + .ThrowAsync() + ).Subject.First(); + + exception + .Message.Should() + .Be( + "The database operation was expected to affect 1 row(s), but actually affected 0 row(s). " + + "Data in the database may have been modified or deleted since entities were loaded. See " + + $"{nameof(DbUpdateConcurrencyException)}.{nameof(DbUpdateConcurrencyException.Entity)} for " + + "the entity that was involved in the operation." ); - exception.Entity - .Should().Be(failingEntity); + exception.Entity.Should().Be(failingEntity); foreach (var entity in entitiesToDelete.Except([failingEntity])) { - this.ExistsEntityInDb(entity) - .Should().BeFalse(); + this.ExistsEntityInDb(entity).Should().BeFalse(); } - this.ExistsEntityInDb(failingEntity) - .Should().BeTrue(); + this.ExistsEntityInDb(failingEntity).Should().BeTrue(); } [Theory] @@ -271,23 +237,29 @@ public async Task DeleteEntities_ShouldReturnNumberOfAffectedRows(bool useAsyncA { var entitiesToDelete = this.CreateEntitiesInDb(); - (await this.CallApi( + ( + await this.CallApi( useAsyncApi, this.Connection, entitiesToDelete, null, TestContext.Current.CancellationToken - )) - .Should().Be(entitiesToDelete.Count); + ) + ) + .Should() + .Be(entitiesToDelete.Count); - (await this.CallApi( + ( + await this.CallApi( useAsyncApi, this.Connection, Array.Empty(), null, TestContext.Current.CancellationToken - )) - .Should().Be(0); + ) + ) + .Should() + .Be(0); } [Theory] @@ -309,8 +281,7 @@ await this.CallApi( foreach (var entity in entitiesToDelete) { - this.ExistsEntityInDb(entity, transaction) - .Should().BeFalse(); + this.ExistsEntityInDb(entity, transaction).Should().BeFalse(); } await transaction.RollbackAsync(); @@ -318,8 +289,7 @@ await this.CallApi( foreach (var entity in entitiesToDelete) { - this.ExistsEntityInDb(entity) - .Should().BeTrue(); + this.ExistsEntityInDb(entity).Should().BeTrue(); } } diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntityTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntityTests.cs index bc7f272..8ece3ca 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntityTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntityTests.cs @@ -4,33 +4,27 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.DatabaseAdapters; -public sealed class - EntityManipulator_DeleteEntityTests_MySql : - EntityManipulator_DeleteEntityTests; +public sealed class EntityManipulator_DeleteEntityTests_MySql + : EntityManipulator_DeleteEntityTests; -public sealed class - EntityManipulator_DeleteEntityTests_Oracle : - EntityManipulator_DeleteEntityTests; +public sealed class EntityManipulator_DeleteEntityTests_Oracle + : EntityManipulator_DeleteEntityTests; -public sealed class - EntityManipulator_DeleteEntityTests_PostgreSql : - EntityManipulator_DeleteEntityTests; +public sealed class EntityManipulator_DeleteEntityTests_PostgreSql + : EntityManipulator_DeleteEntityTests; -public sealed class - EntityManipulator_DeleteEntityTests_Sqlite : - EntityManipulator_DeleteEntityTests; +public sealed class EntityManipulator_DeleteEntityTests_Sqlite + : EntityManipulator_DeleteEntityTests; -public sealed class - EntityManipulator_DeleteEntityTests_SqlServer : - EntityManipulator_DeleteEntityTests; +public sealed class EntityManipulator_DeleteEntityTests_SqlServer + : EntityManipulator_DeleteEntityTests; -public abstract class EntityManipulator_DeleteEntityTests - : IntegrationTestsBase +public abstract class EntityManipulator_DeleteEntityTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { /// - protected EntityManipulator_DeleteEntityTests() => - this.manipulator = this.DatabaseAdapter.EntityManipulator; + protected EntityManipulator_DeleteEntityTests() => this.manipulator = this.DatabaseAdapter.EntityManipulator; [Theory] [InlineData(false)] @@ -45,20 +39,13 @@ public async Task DeleteEntity_CancellationToken_ShouldCancelOperationIfCancella this.DelayNextDbCommand = true; - await Invoking(() => this.CallApi( - useAsyncApi, - this.Connection, - entityToDelete, - null, - cancellationToken - ) - ) - .Should().ThrowAsync() + await Invoking(() => this.CallApi(useAsyncApi, this.Connection, entityToDelete, null, cancellationToken)) + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); // Since the operation was cancelled, the entity should still exist. - this.ExistsEntityInDb(entityToDelete) - .Should().BeTrue(); + this.ExistsEntityInDb(entityToDelete).Should().BeTrue(); } [Theory] @@ -69,29 +56,32 @@ public async Task DeleteEntity_ConcurrencyTokenMismatch_ShouldThrow(bool useAsyn var entityToDelete = this.CreateEntityInDb(); entityToDelete.ConcurrencyToken_ = Generate.Single(); - var exception = (await Invoking(() => this.CallApi( - useAsyncApi, - this.Connection, - entityToDelete, - null, - TestContext.Current.CancellationToken + var exception = ( + await Invoking(() => + this.CallApi( + useAsyncApi, + this.Connection, + entityToDelete, + null, + TestContext.Current.CancellationToken + ) ) - ) - .Should().ThrowAsync()).Subject.First(); - - exception.Message - .Should().Be( - "The database operation was expected to affect 1 row(s), but actually affected 0 row(s). " + - "Data in the database may have been modified or deleted since entities were loaded. See " + - $"{nameof(DbUpdateConcurrencyException)}.{nameof(DbUpdateConcurrencyException.Entity)} for " + - "the entity that was involved in the operation." + .Should() + .ThrowAsync() + ).Subject.First(); + + exception + .Message.Should() + .Be( + "The database operation was expected to affect 1 row(s), but actually affected 0 row(s). " + + "Data in the database may have been modified or deleted since entities were loaded. See " + + $"{nameof(DbUpdateConcurrencyException)}.{nameof(DbUpdateConcurrencyException.Entity)} for " + + "the entity that was involved in the operation." ); - exception.Entity - .Should().Be(entityToDelete); + exception.Entity.Should().Be(entityToDelete); - this.ExistsEntityInDb(entityToDelete) - .Should().BeTrue(); + this.ExistsEntityInDb(entityToDelete).Should().BeTrue(); } [Theory] @@ -103,19 +93,11 @@ public async Task DeleteEntity_Mapping_Attributes_ShouldUseAttributesMapping(boo var entityToDelete = entities[0]; var entityToKeep = entities[1]; - await this.CallApi( - useAsyncApi, - this.Connection, - entityToDelete, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, entityToDelete, null, TestContext.Current.CancellationToken); - this.ExistsEntityInDb(entityToDelete) - .Should().BeFalse(); + this.ExistsEntityInDb(entityToDelete).Should().BeFalse(); - this.ExistsEntityInDb(entityToKeep) - .Should().BeTrue(); + this.ExistsEntityInDb(entityToKeep).Should().BeTrue(); } [Theory] @@ -129,19 +111,11 @@ public async Task DeleteEntity_Mapping_FluentApi_ShouldUseFluentApiMapping(bool var entityToDelete = entities[0]; var entityToKeep = entities[1]; - await this.CallApi( - useAsyncApi, - this.Connection, - entityToDelete, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, entityToDelete, null, TestContext.Current.CancellationToken); - this.ExistsEntityInDb(entityToDelete) - .Should().BeFalse(); + this.ExistsEntityInDb(entityToDelete).Should().BeFalse(); - this.ExistsEntityInDb(entityToKeep) - .Should().BeTrue(); + this.ExistsEntityInDb(entityToKeep).Should().BeTrue(); } [Theory] @@ -151,7 +125,8 @@ public Task DeleteEntity_Mapping_MissingKeyProperty_ShouldThrow(bool useAsyncApi { var entityWithoutKeyProperty = new EntityWithoutKeyProperty(); - return Invoking(() => this.CallApi( + return Invoking(() => + this.CallApi( useAsyncApi, this.Connection, entityWithoutKeyProperty, @@ -159,10 +134,11 @@ public Task DeleteEntity_Mapping_MissingKeyProperty_ShouldThrow(bool useAsyncApi TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"No property of the type {typeof(EntityWithoutKeyProperty)} is configured as a key property. Make " + - "sure that at least one instance property of that type is configured as key property." + $"No property of the type {typeof(EntityWithoutKeyProperty)} is configured as a key property. Make " + + "sure that at least one instance property of that type is configured as key property." ); } @@ -175,19 +151,11 @@ public async Task DeleteEntity_Mapping_NoMapping_ShouldUseEntityTypeNameAndPrope var entityToDelete = entities[0]; var entityToKeep = entities[1]; - await this.CallApi( - useAsyncApi, - this.Connection, - entityToDelete, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, entityToDelete, null, TestContext.Current.CancellationToken); - this.ExistsEntityInDb(entityToDelete) - .Should().BeFalse(); + this.ExistsEntityInDb(entityToDelete).Should().BeFalse(); - this.ExistsEntityInDb(entityToKeep) - .Should().BeTrue(); + this.ExistsEntityInDb(entityToKeep).Should().BeTrue(); } [Theory] @@ -198,29 +166,32 @@ public async Task DeleteEntity_RowVersionMismatch_ShouldThrow(bool useAsyncApi) var entityToDelete = this.CreateEntityInDb(); entityToDelete.RowVersion_ = Generate.Single(); - var exception = (await Invoking(() => this.CallApi( - useAsyncApi, - this.Connection, - entityToDelete, - null, - TestContext.Current.CancellationToken + var exception = ( + await Invoking(() => + this.CallApi( + useAsyncApi, + this.Connection, + entityToDelete, + null, + TestContext.Current.CancellationToken + ) ) - ) - .Should().ThrowAsync()).Subject.First(); - - exception.Message - .Should().Be( - "The database operation was expected to affect 1 row(s), but actually affected 0 row(s). " + - "Data in the database may have been modified or deleted since entities were loaded. See " + - $"{nameof(DbUpdateConcurrencyException)}.{nameof(DbUpdateConcurrencyException.Entity)} for " + - "the entity that was involved in the operation." + .Should() + .ThrowAsync() + ).Subject.First(); + + exception + .Message.Should() + .Be( + "The database operation was expected to affect 1 row(s), but actually affected 0 row(s). " + + "Data in the database may have been modified or deleted since entities were loaded. See " + + $"{nameof(DbUpdateConcurrencyException)}.{nameof(DbUpdateConcurrencyException.Entity)} for " + + "the entity that was involved in the operation." ); - exception.Entity - .Should().Be(entityToDelete); + exception.Entity.Should().Be(entityToDelete); - this.ExistsEntityInDb(entityToDelete) - .Should().BeTrue(); + this.ExistsEntityInDb(entityToDelete).Should().BeTrue(); } [Theory] @@ -230,14 +201,9 @@ public async Task DeleteEntity_ShouldReturnNumberOfAffectedRows(bool useAsyncApi { var entityToDelete = this.CreateEntityInDb(); - (await this.CallApi( - useAsyncApi, - this.Connection, - entityToDelete, - null, - TestContext.Current.CancellationToken - )) - .Should().Be(1); + (await this.CallApi(useAsyncApi, this.Connection, entityToDelete, null, TestContext.Current.CancellationToken)) + .Should() + .Be(1); } [Theory] @@ -257,14 +223,12 @@ await this.CallApi( TestContext.Current.CancellationToken ); - this.ExistsEntityInDb(entityToDelete, transaction) - .Should().BeFalse(); + this.ExistsEntityInDb(entityToDelete, transaction).Should().BeFalse(); await transaction.RollbackAsync(); } - this.ExistsEntityInDb(entityToDelete) - .Should().BeTrue(); + this.ExistsEntityInDb(entityToDelete).Should().BeTrue(); } private Task CallApi( @@ -283,9 +247,7 @@ private Task CallApi( try { - return Task.FromResult( - this.manipulator.DeleteEntity(connection, entity, transaction, cancellationToken) - ); + return Task.FromResult(this.manipulator.DeleteEntity(connection, entity, transaction, cancellationToken)); } catch (Exception ex) { diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntitiesTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntitiesTests.cs index 013bc04..8cc4115 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntitiesTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntitiesTests.cs @@ -3,40 +3,32 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.DatabaseAdapters; -public sealed class - EntityManipulator_InsertEntitiesTests_MySql : - EntityManipulator_InsertEntitiesTests; +public sealed class EntityManipulator_InsertEntitiesTests_MySql + : EntityManipulator_InsertEntitiesTests; -public sealed class - EntityManipulator_InsertEntitiesTests_Oracle : - EntityManipulator_InsertEntitiesTests; +public sealed class EntityManipulator_InsertEntitiesTests_Oracle + : EntityManipulator_InsertEntitiesTests; -public sealed class - EntityManipulator_InsertEntitiesTests_PostgreSql : - EntityManipulator_InsertEntitiesTests; +public sealed class EntityManipulator_InsertEntitiesTests_PostgreSql + : EntityManipulator_InsertEntitiesTests; -public sealed class - EntityManipulator_InsertEntitiesTests_Sqlite : - EntityManipulator_InsertEntitiesTests; +public sealed class EntityManipulator_InsertEntitiesTests_Sqlite + : EntityManipulator_InsertEntitiesTests; -public sealed class - EntityManipulator_InsertEntitiesTests_SqlServer : - EntityManipulator_InsertEntitiesTests; +public sealed class EntityManipulator_InsertEntitiesTests_SqlServer + : EntityManipulator_InsertEntitiesTests; -public abstract class EntityManipulator_InsertEntitiesTests - : IntegrationTestsBase +public abstract class EntityManipulator_InsertEntitiesTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { /// - protected EntityManipulator_InsertEntitiesTests() => - this.manipulator = this.DatabaseAdapter.EntityManipulator; + protected EntityManipulator_InsertEntitiesTests() => this.manipulator = this.DatabaseAdapter.EntityManipulator; [Theory] [InlineData(false)] [InlineData(true)] - public async Task InsertEntities_CancellationToken_ShouldCancelOperationIfCancellationIsRequested( - bool useAsyncApi - ) + public async Task InsertEntities_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -46,44 +38,39 @@ bool useAsyncApi this.DelayNextDbCommand = true; - await Invoking(() => - this.CallApi(useAsyncApi, this.Connection, entities, null, cancellationToken) - ) - .Should().ThrowAsync() + await Invoking(() => this.CallApi(useAsyncApi, this.Connection, entities, null, cancellationToken)) + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); // Since the operation was cancelled, the entities should not have been inserted. foreach (var entityToInsert in entities) { - this.ExistsEntityInDb(entityToInsert) - .Should().BeFalse(); + this.ExistsEntityInDb(entityToInsert).Should().BeFalse(); } } [Theory] [InlineData(false)] [InlineData(true)] - public async Task InsertEntities_EnumSerializationModeIsIntegers_ShouldStoreEnumValuesAsIntegers( - bool useAsyncApi - ) + public async Task InsertEntities_EnumSerializationModeIsIntegers_ShouldStoreEnumValuesAsIntegers(bool useAsyncApi) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Integers; var entities = Generate.Multiple(); - await this.CallApi( - useAsyncApi, - this.Connection, - entities, - null, - TestContext.Current.CancellationToken - ); - - (await this.Connection.QueryAsync( - $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsInteger")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities.Select(a => (int)a.Enum)); + await this.CallApi(useAsyncApi, this.Connection, entities, null, TestContext.Current.CancellationToken); + + ( + await this + .Connection.QueryAsync( + $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsInteger")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities.Select(a => (int)a.Enum)); } [Theory] @@ -95,19 +82,18 @@ public async Task InsertEntities_EnumSerializationModeIsStrings_ShouldStoreEnumV var entities = Generate.Multiple(); - await this.CallApi( - useAsyncApi, - this.Connection, - entities, - null, - TestContext.Current.CancellationToken - ); - - (await this.Connection.QueryAsync( - $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsString")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities.Select(a => a.Enum.ToString())); + await this.CallApi(useAsyncApi, this.Connection, entities, null, TestContext.Current.CancellationToken); + + ( + await this + .Connection.QueryAsync( + $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsString")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities.Select(a => a.Enum.ToString())); } [Theory] @@ -117,26 +103,22 @@ public async Task InsertEntities_Mapping_Attributes_ShouldUseAttributesMapping(b { var entities = Generate.Multiple(); entities.ForEach(a => - { - a.Computed_ = 0; - a.Identity_ = 0; - a.NotMapped = "ShouldNotBePersisted"; - } - ); + { + a.Computed_ = 0; + a.Identity_ = 0; + a.NotMapped = "ShouldNotBePersisted"; + }); - await this.CallApi( - useAsyncApi, - this.Connection, - entities, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, entities, null, TestContext.Current.CancellationToken); this.Connection.Query($"SELECT * FROM {Q("MappingTestEntity")}") - .Should().BeEquivalentTo( + .Should() + .BeEquivalentTo( entities, - options => options.Using(context => context.Subject.Should().BeNull()) - .When(info => info.Path.EndsWith("NotMapped")) + options => + options + .Using(context => context.Subject.Should().BeNull()) + .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -149,26 +131,22 @@ public async Task InsertEntities_Mapping_FluentApi_ShouldUseFluentApiMapping(boo var entities = Generate.Multiple(); entities.ForEach(a => - { - a.Computed_ = 0; - a.Identity_ = 0; - a.NotMapped = "ShouldNotBePersisted"; - } - ); + { + a.Computed_ = 0; + a.Identity_ = 0; + a.NotMapped = "ShouldNotBePersisted"; + }); - await this.CallApi( - useAsyncApi, - this.Connection, - entities, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, entities, null, TestContext.Current.CancellationToken); this.Connection.Query($"SELECT * FROM {Q("MappingTestEntity")}") - .Should().BeEquivalentTo( + .Should() + .BeEquivalentTo( entities, - options => options.Using(context => context.Subject.Should().BeNull()) - .When(info => info.Path.EndsWith("NotMapped")) + options => + options + .Using(context => context.Subject.Should().BeNull()) + .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -179,16 +157,11 @@ public async Task InsertEntities_Mapping_NoMapping_ShouldUseEntityTypeNameAndPro { var entities = Generate.Multiple(); - await this.CallApi( - useAsyncApi, - this.Connection, - entities, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, entities, null, TestContext.Current.CancellationToken); this.Connection.Query($"SELECT * FROM {Q("MappingTestEntity")}") - .Should().BeEquivalentTo(entities); + .Should() + .BeEquivalentTo(entities); } [Theory] @@ -198,20 +171,20 @@ public async Task InsertEntities_ShouldInsertEntities(bool useAsyncApi) { var entities = Generate.Multiple(); - (await this.CallApi( - useAsyncApi, - this.Connection, - entities, - null, - TestContext.Current.CancellationToken - )) - .Should().Be(entities.Count); - - (await this.Connection.QueryAsync( - $"SELECT * FROM {Q("Entity")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities); + (await this.CallApi(useAsyncApi, this.Connection, entities, null, TestContext.Current.CancellationToken)) + .Should() + .Be(entities.Count); + + ( + await this + .Connection.QueryAsync( + $"SELECT * FROM {Q("Entity")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities); } [Theory] @@ -221,23 +194,21 @@ public async Task InsertEntities_ShouldReturnNumberOfAffectedRows(bool useAsyncA { var entities = Generate.Multiple(); - (await this.CallApi( - useAsyncApi, - this.Connection, - entities, - null, - TestContext.Current.CancellationToken - )) - .Should().Be(entities.Count); + (await this.CallApi(useAsyncApi, this.Connection, entities, null, TestContext.Current.CancellationToken)) + .Should() + .Be(entities.Count); - (await this.CallApi( + ( + await this.CallApi( useAsyncApi, this.Connection, Array.Empty(), null, TestContext.Current.CancellationToken - )) - .Should().Be(0); + ) + ) + .Should() + .Be(0); } [Theory] @@ -249,19 +220,18 @@ public async Task InsertEntities_ShouldSupportDateTimeOffsetValues(bool useAsync var entities = Generate.Multiple(); - await this.CallApi( - useAsyncApi, - this.Connection, - entities, - null, - TestContext.Current.CancellationToken - ); - - (await this.Connection.QueryAsync( - $"SELECT * FROM {Q("EntityWithDateTimeOffset")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities); + await this.CallApi(useAsyncApi, this.Connection, entities, null, TestContext.Current.CancellationToken); + + ( + await this + .Connection.QueryAsync( + $"SELECT * FROM {Q("EntityWithDateTimeOffset")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities); } [Theory] @@ -273,19 +243,21 @@ public async Task InsertEntities_Transaction_ShouldUseTransaction(bool useAsyncA await using (var transaction = await this.Connection.BeginTransactionAsync()) { - (await this.CallApi( + ( + await this.CallApi( useAsyncApi, this.Connection, entities, transaction, TestContext.Current.CancellationToken - )) - .Should().Be(entities.Count); + ) + ) + .Should() + .Be(entities.Count); foreach (var entity in entities) { - this.ExistsEntityInDb(entity, transaction) - .Should().BeTrue(); + this.ExistsEntityInDb(entity, transaction).Should().BeTrue(); } await transaction.RollbackAsync(); @@ -293,8 +265,7 @@ public async Task InsertEntities_Transaction_ShouldUseTransaction(bool useAsyncA foreach (var entity in entities) { - this.ExistsEntityInDb(entity) - .Should().BeFalse(); + this.ExistsEntityInDb(entity).Should().BeFalse(); } } diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntityTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntityTests.cs index 5f148e9..68fd430 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntityTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntityTests.cs @@ -3,33 +3,27 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.DatabaseAdapters; -public sealed class - EntityManipulator_InsertEntityTests_MySql : - EntityManipulator_InsertEntityTests; +public sealed class EntityManipulator_InsertEntityTests_MySql + : EntityManipulator_InsertEntityTests; -public sealed class - EntityManipulator_InsertEntityTests_Oracle : - EntityManipulator_InsertEntityTests; +public sealed class EntityManipulator_InsertEntityTests_Oracle + : EntityManipulator_InsertEntityTests; -public sealed class - EntityManipulator_InsertEntityTests_PostgreSql : - EntityManipulator_InsertEntityTests; +public sealed class EntityManipulator_InsertEntityTests_PostgreSql + : EntityManipulator_InsertEntityTests; -public sealed class - EntityManipulator_InsertEntityTests_Sqlite : - EntityManipulator_InsertEntityTests; +public sealed class EntityManipulator_InsertEntityTests_Sqlite + : EntityManipulator_InsertEntityTests; -public sealed class - EntityManipulator_InsertEntityTests_SqlServer : - EntityManipulator_InsertEntityTests; +public sealed class EntityManipulator_InsertEntityTests_SqlServer + : EntityManipulator_InsertEntityTests; -public abstract class EntityManipulator_InsertEntityTests - : IntegrationTestsBase +public abstract class EntityManipulator_InsertEntityTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { /// - protected EntityManipulator_InsertEntityTests() => - this.manipulator = this.DatabaseAdapter.EntityManipulator; + protected EntityManipulator_InsertEntityTests() => this.manipulator = this.DatabaseAdapter.EntityManipulator; [Theory] [InlineData(false)] @@ -44,15 +38,13 @@ public async Task InsertEntity_CancellationToken_ShouldCancelOperationIfCancella this.DelayNextDbCommand = true; - await Invoking(() => - this.CallApi(useAsyncApi, this.Connection, entity, null, cancellationToken) - ) - .Should().ThrowAsync() + await Invoking(() => this.CallApi(useAsyncApi, this.Connection, entity, null, cancellationToken)) + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); // Since the operation was cancelled, the entity should not have been inserted. - this.ExistsEntityInDb(entity) - .Should().BeFalse(); + this.ExistsEntityInDb(entity).Should().BeFalse(); } [Theory] @@ -66,11 +58,14 @@ public async Task InsertEntity_EnumSerializationModeIsIntegers_ShouldStoreEnumVa await this.CallApi(useAsyncApi, this.Connection, entity, null, TestContext.Current.CancellationToken); - (await this.Connection.QuerySingleAsync( + ( + await this.Connection.QuerySingleAsync( $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsInteger")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be((int)entity.Enum); + ) + ) + .Should() + .Be((int)entity.Enum); } [Theory] @@ -84,11 +79,14 @@ public async Task InsertEntity_EnumSerializationModeIsStrings_ShouldStoreEnumVal await this.CallApi(useAsyncApi, this.Connection, entity, null, TestContext.Current.CancellationToken); - (await this.Connection.QuerySingleAsync( + ( + await this.Connection.QuerySingleAsync( $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsString")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity.Enum.ToString()); + ) + ) + .Should() + .BeEquivalentTo(entity.Enum.ToString()); } [Theory] @@ -101,19 +99,16 @@ public async Task InsertEntity_Mapping_Attributes_ShouldUseAttributesMapping(boo entity.Identity_ = 0; entity.NotMapped = "ShouldNotBePersisted"; - await this.CallApi( - useAsyncApi, - this.Connection, - entity, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, entity, null, TestContext.Current.CancellationToken); (await this.Connection.QueryFirstAsync($"SELECT * FROM {Q("MappingTestEntity")}")) - .Should().BeEquivalentTo( + .Should() + .BeEquivalentTo( entity, - options => options.Using(context => context.Subject.Should().BeNull()) - .When(info => info.Path.EndsWith("NotMapped")) + options => + options + .Using(context => context.Subject.Should().BeNull()) + .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -129,19 +124,16 @@ public async Task InsertEntity_Mapping_FluentApi_ShouldUseFluentApiMapping(bool entity.Identity_ = 0; entity.NotMapped = "ShouldNotBePersisted"; - await this.CallApi( - useAsyncApi, - this.Connection, - entity, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, entity, null, TestContext.Current.CancellationToken); (await this.Connection.QueryFirstAsync($"SELECT * FROM {Q("MappingTestEntity")}")) - .Should().BeEquivalentTo( + .Should() + .BeEquivalentTo( entity, - options => options.Using(context => context.Subject.Should().BeNull()) - .When(info => info.Path.EndsWith("NotMapped")) + options => + options + .Using(context => context.Subject.Should().BeNull()) + .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -152,16 +144,11 @@ public async Task InsertEntity_Mapping_NoMapping_ShouldUseEntityTypeNameAndPrope { var entity = Generate.Single(); - await this.CallApi( - useAsyncApi, - this.Connection, - entity, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, entity, null, TestContext.Current.CancellationToken); (await this.Connection.QueryFirstAsync($"SELECT * FROM {Q("MappingTestEntity")}")) - .Should().BeEquivalentTo(entity); + .Should() + .BeEquivalentTo(entity); } [Theory] @@ -172,13 +159,17 @@ public async Task InsertEntity_ShouldInsertEntity(bool useAsyncApi) var entity = Generate.Single(); (await this.CallApi(useAsyncApi, this.Connection, entity, null, TestContext.Current.CancellationToken)) - .Should().Be(1); + .Should() + .Be(1); - (await this.Connection.QuerySingleAsync( + ( + await this.Connection.QuerySingleAsync( $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] @@ -189,7 +180,8 @@ public async Task InsertEntity_ShouldReturnNumberOfAffectedRows(bool useAsyncApi var entity = Generate.Single(); (await this.CallApi(useAsyncApi, this.Connection, entity, null, TestContext.Current.CancellationToken)) - .Should().Be(1); + .Should() + .Be(1); } [Theory] @@ -203,11 +195,14 @@ public async Task InsertEntity_ShouldSupportDateTimeOffsetValues(bool useAsyncAp await this.CallApi(useAsyncApi, this.Connection, entity, null, TestContext.Current.CancellationToken); - (await this.Connection.QuerySingleAsync( + ( + await this.Connection.QuerySingleAsync( $"SELECT * FROM {Q("EntityWithDateTimeOffset")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] @@ -219,23 +214,24 @@ public async Task InsertEntity_Transaction_ShouldUseTransaction(bool useAsyncApi await using (var transaction = await this.Connection.BeginTransactionAsync()) { - (await this.CallApi( + ( + await this.CallApi( useAsyncApi, this.Connection, entity, transaction, TestContext.Current.CancellationToken - )) - .Should().Be(1); + ) + ) + .Should() + .Be(1); - this.ExistsEntityInDb(entity, transaction) - .Should().BeTrue(); + this.ExistsEntityInDb(entity, transaction).Should().BeTrue(); await transaction.RollbackAsync(); } - this.ExistsEntityInDb(entity) - .Should().BeFalse(); + this.ExistsEntityInDb(entity).Should().BeFalse(); } private Task CallApi( @@ -254,9 +250,7 @@ private Task CallApi( try { - return Task.FromResult( - this.manipulator.InsertEntity(connection, entity, transaction, cancellationToken) - ); + return Task.FromResult(this.manipulator.InsertEntity(connection, entity, transaction, cancellationToken)); } catch (Exception ex) { diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntitiesTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntitiesTests.cs index 7198578..30e0d5e 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntitiesTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntitiesTests.cs @@ -4,40 +4,32 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.DatabaseAdapters; -public sealed class - EntityManipulator_UpdateEntitiesTests_MySql : - EntityManipulator_UpdateEntitiesTests; +public sealed class EntityManipulator_UpdateEntitiesTests_MySql + : EntityManipulator_UpdateEntitiesTests; -public sealed class - EntityManipulator_UpdateEntitiesTests_Oracle : - EntityManipulator_UpdateEntitiesTests; +public sealed class EntityManipulator_UpdateEntitiesTests_Oracle + : EntityManipulator_UpdateEntitiesTests; -public sealed class - EntityManipulator_UpdateEntitiesTests_PostgreSql : - EntityManipulator_UpdateEntitiesTests; +public sealed class EntityManipulator_UpdateEntitiesTests_PostgreSql + : EntityManipulator_UpdateEntitiesTests; -public sealed class - EntityManipulator_UpdateEntitiesTests_Sqlite : - EntityManipulator_UpdateEntitiesTests; +public sealed class EntityManipulator_UpdateEntitiesTests_Sqlite + : EntityManipulator_UpdateEntitiesTests; -public sealed class - EntityManipulator_UpdateEntitiesTests_SqlServer : - EntityManipulator_UpdateEntitiesTests; +public sealed class EntityManipulator_UpdateEntitiesTests_SqlServer + : EntityManipulator_UpdateEntitiesTests; -public abstract class EntityManipulator_UpdateEntitiesTests - : IntegrationTestsBase +public abstract class EntityManipulator_UpdateEntitiesTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { /// - protected EntityManipulator_UpdateEntitiesTests() => - this.manipulator = this.DatabaseAdapter.EntityManipulator; + protected EntityManipulator_UpdateEntitiesTests() => this.manipulator = this.DatabaseAdapter.EntityManipulator; [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntities_CancellationToken_ShouldCancelOperationIfCancellationIsRequested( - bool useAsyncApi - ) + public async Task UpdateEntities_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -48,18 +40,22 @@ bool useAsyncApi this.DelayNextDbCommand = true; - await Invoking(() => - this.CallApi(useAsyncApi, this.Connection, updatedEntities, null, cancellationToken) - ) - .Should().ThrowAsync() + await Invoking(() => this.CallApi(useAsyncApi, this.Connection, updatedEntities, null, cancellationToken)) + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); // Since the operation was cancelled, the entities should not have been updated. - (await this.Connection.QueryAsync( - $"SELECT * FROM {Q("Entity")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities); + ( + await this + .Connection.QueryAsync( + $"SELECT * FROM {Q("Entity")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities); } [Theory] @@ -73,59 +69,63 @@ public async Task UpdateEntities_ConcurrencyTokenMismatch_ShouldThrow(bool useAs var failingEntity = updatedEntities[^1]; failingEntity.ConcurrencyToken_ = Generate.Single(); - var exception = (await Invoking(() => this.CallApi( - useAsyncApi, - this.Connection, - updatedEntities, - null, - TestContext.Current.CancellationToken + var exception = ( + await Invoking(() => + this.CallApi( + useAsyncApi, + this.Connection, + updatedEntities, + null, + TestContext.Current.CancellationToken + ) ) - ) - .Should().ThrowAsync()).Subject.First(); - - exception.Message - .Should().Be( - "The database operation was expected to affect 1 row(s), but actually affected 0 row(s). " + - "Data in the database may have been modified or deleted since entities were loaded. See " + - $"{nameof(DbUpdateConcurrencyException)}.{nameof(DbUpdateConcurrencyException.Entity)} for " + - "the entity that was involved in the operation." + .Should() + .ThrowAsync() + ).Subject.First(); + + exception + .Message.Should() + .Be( + "The database operation was expected to affect 1 row(s), but actually affected 0 row(s). " + + "Data in the database may have been modified or deleted since entities were loaded. See " + + $"{nameof(DbUpdateConcurrencyException)}.{nameof(DbUpdateConcurrencyException.Entity)} for " + + "the entity that was involved in the operation." ); - exception.Entity - .Should().Be(failingEntity); + exception.Entity.Should().Be(failingEntity); foreach (var entity in updatedEntities.Except([failingEntity])) { - (await this.Connection.QueryFirstAsync( + ( + await this.Connection.QueryFirstAsync( $""" - SELECT * - FROM {Q("MappingTestEntity")} - WHERE {Q("Key1")} = {Parameter(entity.Key1_)} AND - {Q("Key2")} = {Parameter(entity.Key2_)} - """, + SELECT * + FROM {Q("MappingTestEntity")} + WHERE {Q("Key1")} = {Parameter(entity.Key1_)} AND + {Q("Key2")} = {Parameter(entity.Key2_)} + """, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ).Should().BeEquivalentTo(entity); } - (await this.Connection.QueryFirstAsync( + ( + await this.Connection.QueryFirstAsync( $""" - SELECT * - FROM {Q("MappingTestEntity")} - WHERE {Q("Key1")} = {Parameter(failingEntity.Key1_)} AND - {Q("Key2")} = {Parameter(failingEntity.Key2_)} - """, + SELECT * + FROM {Q("MappingTestEntity")} + WHERE {Q("Key1")} = {Parameter(failingEntity.Key1_)} AND + {Q("Key2")} = {Parameter(failingEntity.Key2_)} + """, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[^1]); + ) + ).Should().BeEquivalentTo(entities[^1]); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task UpdateEntities_EnumSerializationModeIsIntegers_ShouldStoreEnumValuesAsIntegers( - bool useAsyncApi - ) + public async Task UpdateEntities_EnumSerializationModeIsIntegers_ShouldStoreEnumValuesAsIntegers(bool useAsyncApi) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Integers; @@ -139,28 +139,32 @@ await this.manipulator.InsertEntitiesAsync( ); // Make sure the enums are stored as integers: - (await this.Connection.QueryAsync( - $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsInteger")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities.Select(a => (int)a.Enum)); + ( + await this + .Connection.QueryAsync( + $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsInteger")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities.Select(a => (int)a.Enum)); var updatedEntities = Generate.UpdateFor(entities); - await this.CallApi( - useAsyncApi, - this.Connection, - updatedEntities, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, updatedEntities, null, TestContext.Current.CancellationToken); // Make sure the enums are stored as integers: - (await this.Connection.QueryAsync( - $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsInteger")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(updatedEntities.Select(a => (int)a.Enum)); + ( + await this + .Connection.QueryAsync( + $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsInteger")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(updatedEntities.Select(a => (int)a.Enum)); } [Theory] @@ -180,28 +184,32 @@ await this.manipulator.InsertEntitiesAsync( ); // Make sure the enums are stored as strings: - (await this.Connection.QueryAsync( - $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsString")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities.Select(a => a.Enum.ToString())); + ( + await this + .Connection.QueryAsync( + $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsString")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities.Select(a => a.Enum.ToString())); var updatedEntities = Generate.UpdateFor(entities); - await this.CallApi( - useAsyncApi, - this.Connection, - updatedEntities, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, updatedEntities, null, TestContext.Current.CancellationToken); // Make sure the enums are stored as strings: - (await this.Connection.QueryAsync( - $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsString")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(updatedEntities.Select(a => a.Enum.ToString())); + ( + await this + .Connection.QueryAsync( + $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsString")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(updatedEntities.Select(a => a.Enum.ToString())); } [Theory] @@ -213,26 +221,21 @@ public async Task UpdateEntities_Mapping_Attributes_ShouldUseAttributesMapping(b var updatedEntities = Generate.UpdateFor(entities); updatedEntities.ForEach(a => - { - a.Computed_ = 0; - a.Identity_ = 0; - a.NotMapped = "ShouldNotBePersisted"; - } - ); + { + a.Computed_ = 0; + a.Identity_ = 0; + a.NotMapped = "ShouldNotBePersisted"; + }); - await this.CallApi( - useAsyncApi, - this.Connection, - updatedEntities, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, updatedEntities, null, TestContext.Current.CancellationToken); this.Connection.Query($"SELECT * FROM {Q("MappingTestEntity")}") - .Should().BeEquivalentTo( + .Should() + .BeEquivalentTo( updatedEntities, options => - options.Using(context => context.Subject.Should().BeNull()) + options + .Using(context => context.Subject.Should().BeNull()) .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -248,26 +251,22 @@ public async Task UpdateEntities_Mapping_FluentApi_ShouldUseFluentApiMapping(boo var updatedEntities = Generate.UpdateFor(entities); updatedEntities.ForEach(a => - { - a.Computed_ = 0; - a.Identity_ = 0; - a.NotMapped = "ShouldNotBePersisted"; - } - ); + { + a.Computed_ = 0; + a.Identity_ = 0; + a.NotMapped = "ShouldNotBePersisted"; + }); - await this.CallApi( - useAsyncApi, - this.Connection, - updatedEntities, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, updatedEntities, null, TestContext.Current.CancellationToken); this.Connection.Query($"SELECT * FROM {Q("MappingTestEntity")}") - .Should().BeEquivalentTo( + .Should() + .BeEquivalentTo( updatedEntities, - options => options.Using(context => context.Subject.Should().BeNull()) - .When(info => info.Path.EndsWith("NotMapped")) + options => + options + .Using(context => context.Subject.Should().BeNull()) + .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -278,7 +277,8 @@ public Task UpdateEntities_Mapping_MissingKeyProperty_ShouldThrow(bool useAsyncA { var entityWithoutKeyProperty = new EntityWithoutKeyProperty(); - return Invoking(() => this.CallApi( + return Invoking(() => + this.CallApi( useAsyncApi, this.Connection, [entityWithoutKeyProperty], @@ -286,10 +286,11 @@ public Task UpdateEntities_Mapping_MissingKeyProperty_ShouldThrow(bool useAsyncA TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"No property of the type {typeof(EntityWithoutKeyProperty)} is configured as a key property. Make " + - "sure that at least one instance property of that type is configured as key property." + $"No property of the type {typeof(EntityWithoutKeyProperty)} is configured as a key property. Make " + + "sure that at least one instance property of that type is configured as key property." ); } @@ -301,16 +302,11 @@ public async Task UpdateEntities_Mapping_NoMapping_ShouldUseEntityTypeNameAndPro var entities = this.CreateEntitiesInDb(); var updatedEntities = Generate.UpdateFor(entities); - await this.CallApi( - useAsyncApi, - this.Connection, - updatedEntities, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, updatedEntities, null, TestContext.Current.CancellationToken); this.Connection.Query($"SELECT * FROM {Q("MappingTestEntity")}") - .Should().BeEquivalentTo(updatedEntities); + .Should() + .BeEquivalentTo(updatedEntities); } [Theory] @@ -324,51 +320,57 @@ public async Task UpdateEntities_RowVersionMismatch_ShouldThrow(bool useAsyncApi var failingEntity = updatedEntities[^1]; failingEntity.RowVersion_ = Generate.Single(); - var exception = (await Invoking(() => this.CallApi( - useAsyncApi, - this.Connection, - updatedEntities, - null, - TestContext.Current.CancellationToken + var exception = ( + await Invoking(() => + this.CallApi( + useAsyncApi, + this.Connection, + updatedEntities, + null, + TestContext.Current.CancellationToken + ) ) - ) - .Should().ThrowAsync()).Subject.First(); - - exception.Message - .Should().Be( - "The database operation was expected to affect 1 row(s), but actually affected 0 row(s). " + - "Data in the database may have been modified or deleted since entities were loaded. See " + - $"{nameof(DbUpdateConcurrencyException)}.{nameof(DbUpdateConcurrencyException.Entity)} for " + - "the entity that was involved in the operation." + .Should() + .ThrowAsync() + ).Subject.First(); + + exception + .Message.Should() + .Be( + "The database operation was expected to affect 1 row(s), but actually affected 0 row(s). " + + "Data in the database may have been modified or deleted since entities were loaded. See " + + $"{nameof(DbUpdateConcurrencyException)}.{nameof(DbUpdateConcurrencyException.Entity)} for " + + "the entity that was involved in the operation." ); - exception.Entity - .Should().Be(failingEntity); + exception.Entity.Should().Be(failingEntity); foreach (var entity in updatedEntities.Except([failingEntity])) { - (await this.Connection.QueryFirstAsync( + ( + await this.Connection.QueryFirstAsync( $""" - SELECT * - FROM {Q("MappingTestEntity")} - WHERE {Q("Key1")} = {Parameter(entity.Key1_)} AND - {Q("Key2")} = {Parameter(entity.Key2_)} - """, + SELECT * + FROM {Q("MappingTestEntity")} + WHERE {Q("Key1")} = {Parameter(entity.Key1_)} AND + {Q("Key2")} = {Parameter(entity.Key2_)} + """, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ).Should().BeEquivalentTo(entity); } - (await this.Connection.QueryFirstAsync( + ( + await this.Connection.QueryFirstAsync( $""" - SELECT * - FROM {Q("MappingTestEntity")} - WHERE {Q("Key1")} = {Parameter(failingEntity.Key1_)} AND - {Q("Key2")} = {Parameter(failingEntity.Key2_)} - """, + SELECT * + FROM {Q("MappingTestEntity")} + WHERE {Q("Key1")} = {Parameter(failingEntity.Key1_)} AND + {Q("Key2")} = {Parameter(failingEntity.Key2_)} + """, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[^1]); + ) + ).Should().BeEquivalentTo(entities[^1]); } [Theory] @@ -379,23 +381,21 @@ public async Task UpdateEntities_ShouldReturnNumberOfAffectedRows(bool useAsyncA var entities = this.CreateEntitiesInDb(); var updatedEntities = Generate.UpdateFor(entities); - (await this.CallApi( - useAsyncApi, - this.Connection, - updatedEntities, - null, - TestContext.Current.CancellationToken - )) - .Should().Be(entities.Count); + (await this.CallApi(useAsyncApi, this.Connection, updatedEntities, null, TestContext.Current.CancellationToken)) + .Should() + .Be(entities.Count); - (await this.CallApi( + ( + await this.CallApi( useAsyncApi, this.Connection, Array.Empty(), null, TestContext.Current.CancellationToken - )) - .Should().Be(0); + ) + ) + .Should() + .Be(0); } [Theory] @@ -408,19 +408,18 @@ public async Task UpdateEntities_ShouldSupportDateTimeOffsetValues(bool useAsync var entities = this.CreateEntitiesInDb(); var updatedEntities = Generate.UpdateFor(entities); - await this.CallApi( - useAsyncApi, - this.Connection, - updatedEntities, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, updatedEntities, null, TestContext.Current.CancellationToken); - (await this.Connection.QueryAsync( - $"SELECT * FROM {Q("EntityWithDateTimeOffset")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(updatedEntities); + ( + await this + .Connection.QueryAsync( + $"SELECT * FROM {Q("EntityWithDateTimeOffset")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(updatedEntities); } [Theory] @@ -431,20 +430,20 @@ public async Task UpdateEntities_ShouldUpdateEntities(bool useAsyncApi) var entities = this.CreateEntitiesInDb(); var updatedEntities = Generate.UpdateFor(entities); - (await this.CallApi( - useAsyncApi, - this.Connection, - updatedEntities, - null, - TestContext.Current.CancellationToken - )) - .Should().Be(updatedEntities.Count); + (await this.CallApi(useAsyncApi, this.Connection, updatedEntities, null, TestContext.Current.CancellationToken)) + .Should() + .Be(updatedEntities.Count); - (await this.Connection.QueryAsync( - $"SELECT * FROM {Q("Entity")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(updatedEntities); + ( + await this + .Connection.QueryAsync( + $"SELECT * FROM {Q("Entity")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(updatedEntities); } [Theory] @@ -458,25 +457,36 @@ public async Task UpdateEntities_Transaction_ShouldUseTransaction(bool useAsyncA { var updatedEntities = Generate.UpdateFor(entities); - (await this.CallApi( + ( + await this.CallApi( useAsyncApi, this.Connection, updatedEntities, transaction, TestContext.Current.CancellationToken - )) - .Should().Be(entities.Count); + ) + ) + .Should() + .Be(entities.Count); - (await this.Connection.QueryAsync($"SELECT * FROM {Q("Entity")}", transaction) - .ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(updatedEntities); + ( + await this + .Connection.QueryAsync($"SELECT * FROM {Q("Entity")}", transaction) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(updatedEntities); await transaction.RollbackAsync(); } - (await this.Connection.QueryAsync($"SELECT * FROM {Q("Entity")}") - .ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities); + ( + await this + .Connection.QueryAsync($"SELECT * FROM {Q("Entity")}") + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities); } private Task CallApi( diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntityTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntityTests.cs index c5ff9ad..cb23166 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntityTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntityTests.cs @@ -4,33 +4,27 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.DatabaseAdapters; -public sealed class - EntityManipulator_UpdateEntityTests_MySql : - EntityManipulator_UpdateEntityTests; +public sealed class EntityManipulator_UpdateEntityTests_MySql + : EntityManipulator_UpdateEntityTests; -public sealed class - EntityManipulator_UpdateEntityTests_Oracle : - EntityManipulator_UpdateEntityTests; +public sealed class EntityManipulator_UpdateEntityTests_Oracle + : EntityManipulator_UpdateEntityTests; -public sealed class - EntityManipulator_UpdateEntityTests_PostgreSql : - EntityManipulator_UpdateEntityTests; +public sealed class EntityManipulator_UpdateEntityTests_PostgreSql + : EntityManipulator_UpdateEntityTests; -public sealed class - EntityManipulator_UpdateEntityTests_Sqlite : - EntityManipulator_UpdateEntityTests; +public sealed class EntityManipulator_UpdateEntityTests_Sqlite + : EntityManipulator_UpdateEntityTests; -public sealed class - EntityManipulator_UpdateEntityTests_SqlServer : - EntityManipulator_UpdateEntityTests; +public sealed class EntityManipulator_UpdateEntityTests_SqlServer + : EntityManipulator_UpdateEntityTests; -public abstract class EntityManipulator_UpdateEntityTests - : IntegrationTestsBase +public abstract class EntityManipulator_UpdateEntityTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { /// - protected EntityManipulator_UpdateEntityTests() => - this.manipulator = this.DatabaseAdapter.EntityManipulator; + protected EntityManipulator_UpdateEntityTests() => this.manipulator = this.DatabaseAdapter.EntityManipulator; [Theory] [InlineData(false)] @@ -46,18 +40,20 @@ public async Task UpdateEntity_CancellationToken_ShouldCancelOperationIfCancella this.DelayNextDbCommand = true; - await Invoking(() => - this.CallApi(useAsyncApi, this.Connection, updatedEntity, null, cancellationToken) - ) - .Should().ThrowAsync() + await Invoking(() => this.CallApi(useAsyncApi, this.Connection, updatedEntity, null, cancellationToken)) + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); // Since the operation was cancelled, the entity should not have been updated. - (await this.Connection.QuerySingleAsync( + ( + await this.Connection.QuerySingleAsync( $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] @@ -70,37 +66,42 @@ public async Task UpdateEntity_ConcurrencyTokenMismatch_ShouldThrow(bool useAsyn updatedEntity.ConcurrencyToken_ = Generate.Single(); - var exception = (await Invoking(() => this.CallApi( - useAsyncApi, - this.Connection, - updatedEntity, - null, - TestContext.Current.CancellationToken + var exception = ( + await Invoking(() => + this.CallApi( + useAsyncApi, + this.Connection, + updatedEntity, + null, + TestContext.Current.CancellationToken + ) ) - ) - .Should().ThrowAsync()).Subject.First(); - - exception.Message - .Should().Be( - "The database operation was expected to affect 1 row(s), but actually affected 0 row(s). " + - "Data in the database may have been modified or deleted since entities were loaded. See " + - $"{nameof(DbUpdateConcurrencyException)}.{nameof(DbUpdateConcurrencyException.Entity)} for " + - "the entity that was involved in the operation." + .Should() + .ThrowAsync() + ).Subject.First(); + + exception + .Message.Should() + .Be( + "The database operation was expected to affect 1 row(s), but actually affected 0 row(s). " + + "Data in the database may have been modified or deleted since entities were loaded. See " + + $"{nameof(DbUpdateConcurrencyException)}.{nameof(DbUpdateConcurrencyException.Entity)} for " + + "the entity that was involved in the operation." ); - exception.Entity - .Should().Be(updatedEntity); + exception.Entity.Should().Be(updatedEntity); - (await this.Connection.QueryFirstAsync( + ( + await this.Connection.QueryFirstAsync( $""" - SELECT * - FROM {Q("MappingTestEntity")} - WHERE {Q("Key1")} = {Parameter(updatedEntity.Key1_)} AND - {Q("Key2")} = {Parameter(updatedEntity.Key2_)} - """, + SELECT * + FROM {Q("MappingTestEntity")} + WHERE {Q("Key1")} = {Parameter(updatedEntity.Key1_)} AND + {Q("Key2")} = {Parameter(updatedEntity.Key2_)} + """, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ).Should().BeEquivalentTo(entity); } [Theory] @@ -115,28 +116,28 @@ public async Task UpdateEntity_EnumSerializationModeIsIntegers_ShouldStoreEnumVa await this.manipulator.InsertEntityAsync(this.Connection, entity, null, TestContext.Current.CancellationToken); // Make sure the enum is stored as integer: - (await this.Connection.QuerySingleAsync( + ( + await this.Connection.QuerySingleAsync( $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsInteger")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be((int)entity.Enum); + ) + ) + .Should() + .Be((int)entity.Enum); var updatedEntity = Generate.UpdateFor(entity); - await this.CallApi( - useAsyncApi, - this.Connection, - updatedEntity, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, updatedEntity, null, TestContext.Current.CancellationToken); // Make sure the enum is stored as integer: - (await this.Connection.QuerySingleAsync( + ( + await this.Connection.QuerySingleAsync( $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsInteger")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be((int)updatedEntity.Enum); + ) + ) + .Should() + .Be((int)updatedEntity.Enum); } [Theory] @@ -151,28 +152,28 @@ public async Task UpdateEntity_EnumSerializationModeIsStrings_ShouldStoreEnumVal await this.manipulator.InsertEntityAsync(this.Connection, entity, null, TestContext.Current.CancellationToken); // Make sure the enum is stored as string: - (await this.Connection.QuerySingleAsync( + ( + await this.Connection.QuerySingleAsync( $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsString")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity.Enum.ToString()); + ) + ) + .Should() + .BeEquivalentTo(entity.Enum.ToString()); var updatedEntity = Generate.UpdateFor(entity); - await this.CallApi( - useAsyncApi, - this.Connection, - updatedEntity, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, updatedEntity, null, TestContext.Current.CancellationToken); // Make sure the enum is stored as string: - (await this.Connection.QuerySingleAsync( + ( + await this.Connection.QuerySingleAsync( $"SELECT {Q("Enum")} FROM {Q("EntityWithEnumStoredAsString")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(updatedEntity.Enum.ToString()); + ) + ) + .Should() + .BeEquivalentTo(updatedEntity.Enum.ToString()); } [Theory] @@ -187,19 +188,16 @@ public async Task UpdateEntity_Mapping_Attributes_ShouldUseAttributesMapping(boo updatedEntity.Identity_ = 0; updatedEntity.NotMapped = "ShouldNotBePersisted"; - await this.CallApi( - useAsyncApi, - this.Connection, - updatedEntity, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, updatedEntity, null, TestContext.Current.CancellationToken); (await this.Connection.QueryFirstAsync($"SELECT * FROM {Q("MappingTestEntity")}")) - .Should().BeEquivalentTo( + .Should() + .BeEquivalentTo( updatedEntity, - options => options.Using(context => context.Subject.Should().BeNull()) - .When(info => info.Path.EndsWith("NotMapped")) + options => + options + .Using(context => context.Subject.Should().BeNull()) + .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -217,19 +215,16 @@ public async Task UpdateEntity_Mapping_FluentApi_ShouldUseFluentApiMapping(bool updatedEntity.Identity_ = 0; updatedEntity.NotMapped = "ShouldNotBePersisted"; - await this.CallApi( - useAsyncApi, - this.Connection, - updatedEntity, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, updatedEntity, null, TestContext.Current.CancellationToken); (await this.Connection.QueryFirstAsync($"SELECT * FROM {Q("MappingTestEntity")}")) - .Should().BeEquivalentTo( + .Should() + .BeEquivalentTo( updatedEntity, - options => options.Using(context => context.Subject.Should().BeNull()) - .When(info => info.Path.EndsWith("NotMapped")) + options => + options + .Using(context => context.Subject.Should().BeNull()) + .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -240,7 +235,8 @@ public Task UpdateEntity_Mapping_MissingKeyProperty_ShouldThrow(bool useAsyncApi { var entityWithoutKeyProperty = new EntityWithoutKeyProperty(); - return Invoking(() => this.CallApi( + return Invoking(() => + this.CallApi( useAsyncApi, this.Connection, entityWithoutKeyProperty, @@ -248,10 +244,11 @@ public Task UpdateEntity_Mapping_MissingKeyProperty_ShouldThrow(bool useAsyncApi TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"No property of the type {typeof(EntityWithoutKeyProperty)} is configured as a key property. Make " + - "sure that at least one instance property of that type is configured as key property." + $"No property of the type {typeof(EntityWithoutKeyProperty)} is configured as a key property. Make " + + "sure that at least one instance property of that type is configured as key property." ); } @@ -263,16 +260,11 @@ public async Task UpdateEntity_Mapping_NoMapping_ShouldUseEntityTypeNameAndPrope var entity = this.CreateEntityInDb(); var updatedEntity = Generate.UpdateFor(entity); - await this.CallApi( - useAsyncApi, - this.Connection, - updatedEntity, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, updatedEntity, null, TestContext.Current.CancellationToken); (await this.Connection.QueryFirstAsync($"SELECT * FROM {Q("MappingTestEntity")}")) - .Should().BeEquivalentTo(updatedEntity); + .Should() + .BeEquivalentTo(updatedEntity); } [Theory] @@ -285,37 +277,42 @@ public async Task UpdateEntity_RowVersionMismatch_ShouldThrow(bool useAsyncApi) updatedEntity.RowVersion_ = Generate.Single(); - var exception = (await Invoking(() => this.CallApi( - useAsyncApi, - this.Connection, - updatedEntity, - null, - TestContext.Current.CancellationToken + var exception = ( + await Invoking(() => + this.CallApi( + useAsyncApi, + this.Connection, + updatedEntity, + null, + TestContext.Current.CancellationToken + ) ) - ) - .Should().ThrowAsync()).Subject.First(); - - exception.Message - .Should().Be( - "The database operation was expected to affect 1 row(s), but actually affected 0 row(s). " + - "Data in the database may have been modified or deleted since entities were loaded. See " + - $"{nameof(DbUpdateConcurrencyException)}.{nameof(DbUpdateConcurrencyException.Entity)} for " + - "the entity that was involved in the operation." + .Should() + .ThrowAsync() + ).Subject.First(); + + exception + .Message.Should() + .Be( + "The database operation was expected to affect 1 row(s), but actually affected 0 row(s). " + + "Data in the database may have been modified or deleted since entities were loaded. See " + + $"{nameof(DbUpdateConcurrencyException)}.{nameof(DbUpdateConcurrencyException.Entity)} for " + + "the entity that was involved in the operation." ); - exception.Entity - .Should().Be(updatedEntity); + exception.Entity.Should().Be(updatedEntity); - (await this.Connection.QueryFirstAsync( + ( + await this.Connection.QueryFirstAsync( $""" - SELECT * - FROM {Q("MappingTestEntity")} - WHERE {Q("Key1")} = {Parameter(updatedEntity.Key1_)} AND - {Q("Key2")} = {Parameter(updatedEntity.Key2_)} - """, + SELECT * + FROM {Q("MappingTestEntity")} + WHERE {Q("Key1")} = {Parameter(updatedEntity.Key1_)} AND + {Q("Key2")} = {Parameter(updatedEntity.Key2_)} + """, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ).Should().BeEquivalentTo(entity); } [Theory] @@ -326,14 +323,9 @@ public async Task UpdateEntity_ShouldReturnNumberOfAffectedRows(bool useAsyncApi var entity = this.CreateEntityInDb(); var updatedEntity = Generate.UpdateFor(entity); - (await this.CallApi( - useAsyncApi, - this.Connection, - updatedEntity, - null, - TestContext.Current.CancellationToken - )) - .Should().Be(1); + (await this.CallApi(useAsyncApi, this.Connection, updatedEntity, null, TestContext.Current.CancellationToken)) + .Should() + .Be(1); } [Theory] @@ -346,19 +338,16 @@ public async Task UpdateEntity_ShouldSupportDateTimeOffsetValues(bool useAsyncAp var entity = this.CreateEntityInDb(); var updatedEntity = Generate.UpdateFor(entity); - await this.CallApi( - useAsyncApi, - this.Connection, - updatedEntity, - null, - TestContext.Current.CancellationToken - ); + await this.CallApi(useAsyncApi, this.Connection, updatedEntity, null, TestContext.Current.CancellationToken); - (await this.Connection.QuerySingleAsync( + ( + await this.Connection.QuerySingleAsync( $"SELECT * FROM {Q("EntityWithDateTimeOffset")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(updatedEntity); + ) + ) + .Should() + .BeEquivalentTo(updatedEntity); } [Theory] @@ -369,20 +358,18 @@ public async Task UpdateEntity_ShouldUpdateEntity(bool useAsyncApi) var entity = this.CreateEntityInDb(); var updatedEntity = Generate.UpdateFor(entity); - (await this.CallApi( - useAsyncApi, - this.Connection, - updatedEntity, - null, - TestContext.Current.CancellationToken - )) - .Should().Be(1); + (await this.CallApi(useAsyncApi, this.Connection, updatedEntity, null, TestContext.Current.CancellationToken)) + .Should() + .Be(1); - (await this.Connection.QuerySingleAsync( + ( + await this.Connection.QuerySingleAsync( $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(updatedEntity); + ) + ) + .Should() + .BeEquivalentTo(updatedEntity); } [Theory] @@ -396,23 +383,28 @@ public async Task UpdateEntity_Transaction_ShouldUseTransaction(bool useAsyncApi { var updatedEntity = Generate.UpdateFor(entity); - (await this.CallApi( + ( + await this.CallApi( useAsyncApi, this.Connection, updatedEntity, transaction, TestContext.Current.CancellationToken - )) - .Should().Be(1); + ) + ) + .Should() + .Be(1); (await this.Connection.QuerySingleAsync($"SELECT * FROM {Q("Entity")}", transaction)) - .Should().BeEquivalentTo(updatedEntity); + .Should() + .BeEquivalentTo(updatedEntity); await transaction.RollbackAsync(); } (await this.Connection.QuerySingleAsync($"SELECT * FROM {Q("Entity")}")) - .Should().BeEquivalentTo(entity); + .Should() + .BeEquivalentTo(entity); } private Task CallApi( @@ -431,9 +423,7 @@ private Task CallApi( try { - return Task.FromResult( - this.manipulator.UpdateEntity(connection, entity, transaction, cancellationToken) - ); + return Task.FromResult(this.manipulator.UpdateEntity(connection, entity, transaction, cancellationToken)); } catch (Exception ex) { diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/MySql/MySqlDatabaseAdapterTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/MySql/MySqlDatabaseAdapterTests.cs index afa212b..fd23e97 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/MySql/MySqlDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/MySql/MySqlDatabaseAdapterTests.cs @@ -9,7 +9,6 @@ public void SupportsTemporaryTables_ShouldReturnTrue() { var adapter = new MySqlDatabaseAdapter(); - adapter.SupportsTemporaryTables(this.Connection) - .Should().BeTrue(); + adapter.SupportsTemporaryTables(this.Connection).Should().BeTrue(); } } diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs index 5b87f89..3831875 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs @@ -14,8 +14,7 @@ public void QuoteTemporaryTableName_ShouldQuoteTableName() "SELECT VALUE FROM v$parameter WHERE NAME = 'private_temp_table_prefix'" ); - this.adapter.QuoteTemporaryTableName("TempTable", this.Connection) - .Should().Be($"\"{prefix}TempTable\""); + this.adapter.QuoteTemporaryTableName("TempTable", this.Connection).Should().Be($"\"{prefix}TempTable\""); } [Fact] @@ -26,14 +25,14 @@ public void WasSqlStatementCancelledByCancellationToken_StatementWasCancelled_Sh var cancellationToken = CreateCancellationTokenThatIsCancelledAfter100Milliseconds(); - using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); + using var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation( + command, + cancellationToken + ); - var exception = Invoking(() => command.ExecuteNonQuery()) - .Should().Throw().Subject.First(); + var exception = Invoking(() => command.ExecuteNonQuery()).Should().Throw().Subject.First(); - this.adapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - .Should().BeTrue(); + this.adapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken).Should().BeTrue(); } [Fact] @@ -42,11 +41,9 @@ public void WasSqlStatementCancelledByCancellationToken_StatementWasNotCancelled using var command = this.Connection.CreateCommand(); command.CommandText = "InvalidStatement"; - var exception = Invoking(() => command.ExecuteNonQuery()) - .Should().Throw().Subject.First(); + var exception = Invoking(() => command.ExecuteNonQuery()).Should().Throw().Subject.First(); - this.adapter.WasSqlStatementCancelledByCancellationToken(exception, CancellationToken.None) - .Should().BeFalse(); + this.adapter.WasSqlStatementCancelledByCancellationToken(exception, CancellationToken.None).Should().BeFalse(); } private readonly OracleDatabaseAdapter adapter = new(); diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/PostgreSql/PostgreSqlDatabaseAdapterTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/PostgreSql/PostgreSqlDatabaseAdapterTests.cs index 04800ab..ec98e3f 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/PostgreSql/PostgreSqlDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/PostgreSql/PostgreSqlDatabaseAdapterTests.cs @@ -9,8 +9,7 @@ public class PostgreSqlDatabaseAdapterTests : IntegrationTestsBase - this.adapter.SupportsTemporaryTables(this.Connection) - .Should().BeTrue(); + this.adapter.SupportsTemporaryTables(this.Connection).Should().BeTrue(); [Fact] public void WasSqlStatementCancelledByCancellationToken_StatementWasCancelled_ShouldReturnTrue() @@ -23,10 +22,11 @@ public void WasSqlStatementCancelledByCancellationToken_StatementWasCancelled_Sh using var registration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); var exception = Invoking(() => command.ExecuteNonQuery()) - .Should().Throw().Subject.First(); + .Should() + .Throw() + .Subject.First(); - this.adapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - .Should().BeTrue(); + this.adapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken).Should().BeTrue(); } [Fact] @@ -35,11 +35,9 @@ public void WasSqlStatementCancelledByCancellationToken_StatementWasNotCancelled using var command = this.Connection.CreateCommand(); command.CommandText = "InvalidStatement"; - var exception = Invoking(() => command.ExecuteNonQuery()) - .Should().Throw().Subject.First(); + var exception = Invoking(() => command.ExecuteNonQuery()).Should().Throw().Subject.First(); - this.adapter.WasSqlStatementCancelledByCancellationToken(exception, CancellationToken.None) - .Should().BeFalse(); + this.adapter.WasSqlStatementCancelledByCancellationToken(exception, CancellationToken.None).Should().BeFalse(); } private readonly PostgreSqlDatabaseAdapter adapter = new(); diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/SqlServer/SqlServerDatabaseAdapterTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/SqlServer/SqlServerDatabaseAdapterTests.cs index 88ea1b5..bdcb739 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/SqlServer/SqlServerDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/SqlServer/SqlServerDatabaseAdapterTests.cs @@ -8,8 +8,7 @@ public class SqlServerDatabaseAdapterTests : IntegrationTestsBase - this.adapter.SupportsTemporaryTables(this.Connection) - .Should().BeTrue(); + this.adapter.SupportsTemporaryTables(this.Connection).Should().BeTrue(); [Fact] public void WasSqlStatementCancelledByCancellationToken_StatementWasCancelled_ShouldReturnTrue() @@ -21,11 +20,9 @@ public void WasSqlStatementCancelledByCancellationToken_StatementWasCancelled_Sh using var registration = DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); - var exception = Invoking(() => command.ExecuteNonQuery()) - .Should().Throw().Subject.First(); + var exception = Invoking(() => command.ExecuteNonQuery()).Should().Throw().Subject.First(); - this.adapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - .Should().BeTrue(); + this.adapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken).Should().BeTrue(); } [Fact] @@ -34,11 +31,9 @@ public void WasSqlStatementCancelledByCancellationToken_StatementWasNotCancelled using var command = this.Connection.CreateCommand(); command.CommandText = "InvalidStatement"; - var exception = Invoking(() => command.ExecuteNonQuery()) - .Should().Throw().Subject.First(); + var exception = Invoking(() => command.ExecuteNonQuery()).Should().Throw().Subject.First(); - this.adapter.WasSqlStatementCancelledByCancellationToken(exception, CancellationToken.None) - .Should().BeFalse(); + this.adapter.WasSqlStatementCancelledByCancellationToken(exception, CancellationToken.None).Should().BeFalse(); } private readonly SqlServerDatabaseAdapter adapter = new(); diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/Sqlite/SqliteDatabaseAdapterTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/Sqlite/SqliteDatabaseAdapterTests.cs index e80324d..d279be9 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/Sqlite/SqliteDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/Sqlite/SqliteDatabaseAdapterTests.cs @@ -9,7 +9,6 @@ public void SupportsTemporaryTables_ShouldReturnTrue() { var adapter = new SqliteDatabaseAdapter(); - adapter.SupportsTemporaryTables(this.Connection) - .Should().BeTrue(); + adapter.SupportsTemporaryTables(this.Connection).Should().BeTrue(); } } diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/TemporaryTableBuilderTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/TemporaryTableBuilderTests.cs index 91fa738..5aac6d1 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/TemporaryTableBuilderTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/TemporaryTableBuilderTests.cs @@ -6,32 +6,21 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.DatabaseAdapters; -public sealed class - TemporaryTableBuilderTests_MySql : - TemporaryTableBuilderTests; +public sealed class TemporaryTableBuilderTests_MySql : TemporaryTableBuilderTests; -public sealed class - TemporaryTableBuilderTests_Oracle : - TemporaryTableBuilderTests; +public sealed class TemporaryTableBuilderTests_Oracle : TemporaryTableBuilderTests; -public sealed class - TemporaryTableBuilderTests_PostgreSql : - TemporaryTableBuilderTests; +public sealed class TemporaryTableBuilderTests_PostgreSql : TemporaryTableBuilderTests; -public sealed class - TemporaryTableBuilderTests_Sqlite : - TemporaryTableBuilderTests; +public sealed class TemporaryTableBuilderTests_Sqlite : TemporaryTableBuilderTests; -public sealed class - TemporaryTableBuilderTests_SqlServer : - TemporaryTableBuilderTests; +public sealed class TemporaryTableBuilderTests_SqlServer : TemporaryTableBuilderTests; public abstract class TemporaryTableBuilderTests : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { /// - protected TemporaryTableBuilderTests() => - this.builder = this.DatabaseAdapter.TemporaryTableBuilder; + protected TemporaryTableBuilderTests() => this.builder = this.DatabaseAdapter.TemporaryTableBuilder; [Theory] [InlineData(false)] @@ -54,20 +43,24 @@ bool useAsyncApi TestContext.Current.CancellationToken ); - (await this.Connection.QueryAsync( - $"SELECT * FROM {QT("Objects")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(items); + ( + await this + .Connection.QueryAsync( + $"SELECT * FROM {QT("Objects")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(items); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - BuildTemporaryTable_ComplexObjects_EnumSerializationModeIsIntegers_ShouldStoreEnumValuesAsIntegers( - bool useAsyncApi - ) + public async Task BuildTemporaryTable_ComplexObjects_EnumSerializationModeIsIntegers_ShouldStoreEnumValuesAsIntegers( + bool useAsyncApi + ) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Integers; @@ -86,7 +79,8 @@ bool useAsyncApi if (this.TestDatabaseProvider.CanRetrieveStructureOfTemporaryTables) { this.DatabaseAdapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Integers) - .Should().StartWith(this.GetDataTypeOfTemporaryTableColumn("Objects", "Enum")); + .Should() + .StartWith(this.GetDataTypeOfTemporaryTableColumn("Objects", "Enum")); } await using var reader = await this.Connection.ExecuteReaderAsync( @@ -94,25 +88,22 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ); - reader.GetFieldType(0) - .Should().BeAnyOf(typeof(int), typeof(long)); + reader.GetFieldType(0).Should().BeAnyOf(typeof(int), typeof(long)); foreach (var entity in entities) { await reader.ReadAsync(TestContext.Current.CancellationToken); - reader.GetInt32(0) - .Should().Be((int)entity.Enum); + reader.GetInt32(0).Should().Be((int)entity.Enum); } } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - BuildTemporaryTable_ComplexObjects_EnumSerializationModeIsStrings_ShouldStoreEnumValuesAsStrings( - bool useAsyncApi - ) + public async Task BuildTemporaryTable_ComplexObjects_EnumSerializationModeIsStrings_ShouldStoreEnumValuesAsStrings( + bool useAsyncApi + ) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Strings; @@ -131,7 +122,8 @@ bool useAsyncApi if (this.TestDatabaseProvider.CanRetrieveStructureOfTemporaryTables) { this.DatabaseAdapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Strings) - .Should().StartWith(this.GetDataTypeOfTemporaryTableColumn("Objects", "Enum")); + .Should() + .StartWith(this.GetDataTypeOfTemporaryTableColumn("Objects", "Enum")); } await using var reader = await this.Connection.ExecuteReaderAsync( @@ -139,25 +131,22 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ); - reader.GetFieldType(0) - .Should().Be(typeof(string)); + reader.GetFieldType(0).Should().Be(typeof(string)); foreach (var entity in entities) { await reader.ReadAsync(TestContext.Current.CancellationToken); - reader.GetString(0) - .Should().Be(entity.Enum.ToString()); + reader.GetString(0).Should().Be(entity.Enum.ToString()); } } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - BuildTemporaryTable_ComplexObjects_EnumSerializationModeIsStrings_ShouldUseCollationOfDatabaseForEnumColumns( - bool useAsyncApi - ) + public async Task BuildTemporaryTable_ComplexObjects_EnumSerializationModeIsStrings_ShouldUseCollationOfDatabaseForEnumColumns( + bool useAsyncApi + ) { Assert.SkipWhen(this.TestDatabaseProvider.TemporaryTableTextColumnInheritsCollationFromDatabase, ""); @@ -175,16 +164,13 @@ bool useAsyncApi var columnCollation = this.GetCollationOfTemporaryTableColumn("Objects", "Enum"); - columnCollation - .Should().Be(this.TestDatabaseProvider.DatabaseCollation); + columnCollation.Should().Be(this.TestDatabaseProvider.DatabaseCollation); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildTemporaryTable_ComplexObjects_Mapping_Attributes_ShouldUseAttributesMapping( - bool useAsyncApi - ) + public async Task BuildTemporaryTable_ComplexObjects_Mapping_Attributes_ShouldUseAttributesMapping(bool useAsyncApi) { var entities = Generate.Multiple(); entities.ForEach(a => a.NotMapped = "ShouldNotBePersisted"); @@ -204,25 +190,25 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ); - reader.GetFieldNames() - .Should().NotContain(nameof(MappingTestEntityAttributes.NotMapped)); + reader.GetFieldNames().Should().NotContain(nameof(MappingTestEntityAttributes.NotMapped)); await reader.DisposeAsync(); this.Connection.Query($"SELECT * FROM {QT("Objects")}") - .Should().BeEquivalentTo( + .Should() + .BeEquivalentTo( entities, - options => options.Using(context => context.Subject.Should().BeNull()) - .When(info => info.Path.EndsWith("NotMapped")) + options => + options + .Using(context => context.Subject.Should().BeNull()) + .When(info => info.Path.EndsWith("NotMapped")) ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task BuildTemporaryTable_ComplexObjects_Mapping_FluentApi_ShouldUseFluentApiMapping( - bool useAsyncApi - ) + public async Task BuildTemporaryTable_ComplexObjects_Mapping_FluentApi_ShouldUseFluentApiMapping(bool useAsyncApi) { MappingTestEntityFluentApi.Configure(); @@ -244,16 +230,18 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ); - reader.GetFieldNames() - .Should().NotContain(nameof(MappingTestEntityFluentApi.NotMapped)); + reader.GetFieldNames().Should().NotContain(nameof(MappingTestEntityFluentApi.NotMapped)); await reader.DisposeAsync(); this.Connection.Query($"SELECT * FROM {QT("Objects")}") - .Should().BeEquivalentTo( + .Should() + .BeEquivalentTo( entities, - options => options.Using(context => context.Subject.Should().BeNull()) - .When(info => info.Path.EndsWith("NotMapped")) + options => + options + .Using(context => context.Subject.Should().BeNull()) + .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -276,8 +264,7 @@ bool useAsyncApi TestContext.Current.CancellationToken ); - this.Connection.Query($"SELECT * FROM {QT("Objects")}") - .Should().BeEquivalentTo(entities); + this.Connection.Query($"SELECT * FROM {QT("Objects")}").Should().BeEquivalentTo(entities); } [Theory] @@ -297,11 +284,16 @@ public async Task BuildTemporaryTable_ComplexObjects_ShouldCreateMultiColumnTabl TestContext.Current.CancellationToken ); - (await this.Connection.QueryAsync( - $"SELECT * FROM {QT("Objects")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(items); + ( + await this + .Connection.QueryAsync( + $"SELECT * FROM {QT("Objects")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(items); } [Theory] @@ -323,8 +315,7 @@ public async Task BuildTemporaryTable_ComplexObjects_ShouldUseCollationOfDatabas var columnCollation = this.GetCollationOfTemporaryTableColumn("Objects", "StringValue"); - columnCollation - .Should().Be(this.TestDatabaseProvider.DatabaseCollation); + columnCollation.Should().Be(this.TestDatabaseProvider.DatabaseCollation); } [Theory] @@ -344,11 +335,16 @@ public async Task BuildTemporaryTable_ComplexObjects_WithNullables_ShouldHandleN TestContext.Current.CancellationToken ); - (await this.Connection.QueryAsync( - $"SELECT * FROM {QT("Objects")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(itemsWithNulls); + ( + await this + .Connection.QueryAsync( + $"SELECT * FROM {QT("Objects")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(itemsWithNulls); } [Theory] @@ -372,20 +368,24 @@ bool useAsyncApi TestContext.Current.CancellationToken ); - (await this.Connection.QueryAsync( - $"SELECT * FROM {QT("Values")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(values); + ( + await this + .Connection.QueryAsync( + $"SELECT * FROM {QT("Values")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(values); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - BuildTemporaryTable_ScalarValues_EnumSerializationModeIsIntegers_ShouldStoreEnumValuesAsIntegers( - bool useAsyncApi - ) + public async Task BuildTemporaryTable_ScalarValues_EnumSerializationModeIsIntegers_ShouldStoreEnumValuesAsIntegers( + bool useAsyncApi + ) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Integers; @@ -404,7 +404,8 @@ bool useAsyncApi if (this.TestDatabaseProvider.CanRetrieveStructureOfTemporaryTables) { this.DatabaseAdapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Integers) - .Should().StartWith(this.GetDataTypeOfTemporaryTableColumn("Values", "Value")); + .Should() + .StartWith(this.GetDataTypeOfTemporaryTableColumn("Values", "Value")); } await using var reader = await this.Connection.ExecuteReaderAsync( @@ -412,25 +413,22 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ); - reader.GetFieldType(0) - .Should().BeAnyOf(typeof(int), typeof(long)); + reader.GetFieldType(0).Should().BeAnyOf(typeof(int), typeof(long)); foreach (var value in values) { await reader.ReadAsync(TestContext.Current.CancellationToken); - reader.GetInt32(0) - .Should().Be((int)value); + reader.GetInt32(0).Should().Be((int)value); } } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - BuildTemporaryTable_ScalarValues_EnumSerializationModeIsStrings_ShouldStoreEnumValuesAsStrings( - bool useAsyncApi - ) + public async Task BuildTemporaryTable_ScalarValues_EnumSerializationModeIsStrings_ShouldStoreEnumValuesAsStrings( + bool useAsyncApi + ) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Strings; @@ -449,7 +447,8 @@ bool useAsyncApi if (this.TestDatabaseProvider.CanRetrieveStructureOfTemporaryTables) { this.DatabaseAdapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Strings) - .Should().StartWith(this.GetDataTypeOfTemporaryTableColumn("Values", "Value")); + .Should() + .StartWith(this.GetDataTypeOfTemporaryTableColumn("Values", "Value")); } await using var reader = await this.Connection.ExecuteReaderAsync( @@ -457,25 +456,22 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ); - reader.GetFieldType(0) - .Should().Be(typeof(string)); + reader.GetFieldType(0).Should().Be(typeof(string)); foreach (var value in values) { await reader.ReadAsync(TestContext.Current.CancellationToken); - reader.GetString(0) - .Should().Be(value.ToString()); + reader.GetString(0).Should().Be(value.ToString()); } } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - BuildTemporaryTable_ScalarValues_EnumSerializationModeIsStrings_ShouldUseCollationOfDatabaseForEnumColumns( - bool useAsyncApi - ) + public async Task BuildTemporaryTable_ScalarValues_EnumSerializationModeIsStrings_ShouldUseCollationOfDatabaseForEnumColumns( + bool useAsyncApi + ) { Assert.SkipWhen(this.TestDatabaseProvider.TemporaryTableTextColumnInheritsCollationFromDatabase, ""); @@ -493,15 +489,15 @@ bool useAsyncApi var columnCollation = this.GetCollationOfTemporaryTableColumn("Values", "Value"); - columnCollation - .Should().Be(this.TestDatabaseProvider.DatabaseCollation); + columnCollation.Should().Be(this.TestDatabaseProvider.DatabaseCollation); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - BuildTemporaryTable_ScalarValues_NullableEnumValues_ShouldFillTableWithEnumsAndNulls(bool useAsyncApi) + public async Task BuildTemporaryTable_ScalarValues_NullableEnumValues_ShouldFillTableWithEnumsAndNulls( + bool useAsyncApi + ) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Strings; @@ -517,11 +513,16 @@ public async Task TestContext.Current.CancellationToken ); - (await this.Connection.QueryAsync( - $"SELECT {Q("Value")} FROM {QT("Values")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(values); + ( + await this + .Connection.QueryAsync( + $"SELECT {Q("Value")} FROM {QT("Values")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(values); } [Theory] @@ -541,11 +542,16 @@ public async Task BuildTemporaryTable_ScalarValues_ShouldCreateSingleColumnTable TestContext.Current.CancellationToken ); - (await this.Connection.QueryAsync( - $"SELECT {Q("Value")} FROM {QT("Values")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(values); + ( + await this + .Connection.QueryAsync( + $"SELECT {Q("Value")} FROM {QT("Values")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(values); } [Theory] @@ -567,8 +573,7 @@ public async Task BuildTemporaryTable_ScalarValues_ShouldUseCollationOfDatabaseF var columnCollation = this.GetCollationOfTemporaryTableColumn("Values", "Value"); - columnCollation - .Should().Be(this.TestDatabaseProvider.DatabaseCollation); + columnCollation.Should().Be(this.TestDatabaseProvider.DatabaseCollation); } [Theory] @@ -588,11 +593,16 @@ public async Task BuildTemporaryTable_ScalarValuesWithNullValues_ShouldHandleNul TestContext.Current.CancellationToken ); - (await this.Connection.QueryAsync( - $"SELECT {Q("Value")} FROM {QT("NullValues")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(values); + ( + await this + .Connection.QueryAsync( + $"SELECT {Q("Value")} FROM {QT("NullValues")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(values); } [Theory] @@ -610,13 +620,11 @@ public async Task BuildTemporaryTable_ShouldReturnDisposerThatDropsTableAsync(bo TestContext.Current.CancellationToken ); - this.ExistsTemporaryTableInDb("Values") - .Should().BeTrue(); + this.ExistsTemporaryTableInDb("Values").Should().BeTrue(); await disposer.DisposeAsync(); - this.ExistsTemporaryTableInDb("Values") - .Should().BeFalse(); + this.ExistsTemporaryTableInDb("Values").Should().BeFalse(); } private Task CallApi( diff --git a/tests/DbConnectionPlus.IntegrationTests/DbCommands/DbCommandBuilderTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbCommands/DbCommandBuilderTests.cs index 5e9eaba..904a28b 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbCommands/DbCommandBuilderTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbCommands/DbCommandBuilderTests.cs @@ -4,25 +4,15 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.DbCommands; -public sealed class - DbCommandBuilderTests_MySql : - DbCommandBuilderTests; +public sealed class DbCommandBuilderTests_MySql : DbCommandBuilderTests; -public sealed class - DbCommandBuilderTests_Oracle : - DbCommandBuilderTests; +public sealed class DbCommandBuilderTests_Oracle : DbCommandBuilderTests; -public sealed class - DbCommandBuilderTests_PostgreSql : - DbCommandBuilderTests; +public sealed class DbCommandBuilderTests_PostgreSql : DbCommandBuilderTests; -public sealed class - DbCommandBuilderTests_Sqlite : - DbCommandBuilderTests; +public sealed class DbCommandBuilderTests_Sqlite : DbCommandBuilderTests; -public sealed class - DbCommandBuilderTests_SqlServer : - DbCommandBuilderTests; +public sealed class DbCommandBuilderTests_SqlServer : DbCommandBuilderTests; public abstract class DbCommandBuilderTests : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() @@ -38,39 +28,46 @@ public async Task BuildDbCommand_ShouldCreateTemporaryTables(bool useAsyncApi) var entities = Generate.Multiple(); InterpolatedSqlStatement statement = $""" - SELECT Value - FROM {TemporaryTable(entityIds)} AS Ids - INNER JOIN {TemporaryTable(entities)} AS Entities - ON Entities.Id = Ids.Value - """; + SELECT Value + FROM {TemporaryTable(entityIds)} AS Ids + INNER JOIN {TemporaryTable(entities)} AS Entities + ON Entities.Id = Ids.Value + """; var (command, _) = await CallApi(useAsyncApi, statement, this.DatabaseAdapter, this.Connection); var temporaryTables = statement.TemporaryTables; - command.CommandText - .Should().Be( + command + .CommandText.Should() + .Be( $""" - SELECT Value - FROM {QT(temporaryTables[0].Name)} AS Ids - INNER JOIN {QT(temporaryTables[1].Name)} AS Entities - ON Entities.Id = Ids.Value - """ + SELECT Value + FROM {QT(temporaryTables[0].Name)} AS Ids + INNER JOIN {QT(temporaryTables[1].Name)} AS Entities + ON Entities.Id = Ids.Value + """ ); - this.ExistsTemporaryTableInDb(temporaryTables[0].Name) - .Should().BeTrue(); - - this.ExistsTemporaryTableInDb(temporaryTables[1].Name) - .Should().BeTrue(); - - (await this.Connection.QueryAsync($"SELECT {Q("Value")} FROM {QT(temporaryTables[0].Name)}") - .ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entityIds); - - (await this.Connection.QueryAsync($"SELECT * FROM {QT(temporaryTables[1].Name)}") - .ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities); + this.ExistsTemporaryTableInDb(temporaryTables[0].Name).Should().BeTrue(); + + this.ExistsTemporaryTableInDb(temporaryTables[1].Name).Should().BeTrue(); + + ( + await this + .Connection.QueryAsync($"SELECT {Q("Value")} FROM {QT(temporaryTables[0].Name)}") + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entityIds); + + ( + await this + .Connection.QueryAsync($"SELECT * FROM {QT(temporaryTables[1].Name)}") + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities); } [Theory] @@ -84,32 +81,27 @@ public async Task BuildDbCommand_ShouldReturnDisposerForCommandWhichDisposesTemp var entities = Generate.Multiple(); InterpolatedSqlStatement statement = $""" - SELECT Value - FROM {TemporaryTable(entityIds)} AS Ids - INNER JOIN {TemporaryTable(entities)} AS Entities - ON Entities.Id = Ids.Value - """; - var (_, commandDisposer) = - await CallApi(useAsyncApi, statement, this.DatabaseAdapter, this.Connection); + SELECT Value + FROM {TemporaryTable(entityIds)} AS Ids + INNER JOIN {TemporaryTable(entities)} AS Entities + ON Entities.Id = Ids.Value + """; + var (_, commandDisposer) = await CallApi(useAsyncApi, statement, this.DatabaseAdapter, this.Connection); var temporaryTables = statement.TemporaryTables; var table1Name = temporaryTables[0].Name; var table2Name = temporaryTables[1].Name; - this.ExistsTemporaryTableInDb(table1Name) - .Should().BeTrue(); + this.ExistsTemporaryTableInDb(table1Name).Should().BeTrue(); - this.ExistsTemporaryTableInDb(table2Name) - .Should().BeTrue(); + this.ExistsTemporaryTableInDb(table2Name).Should().BeTrue(); await commandDisposer.DisposeAsync(); - this.ExistsTemporaryTableInDb(table1Name) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(table1Name).Should().BeFalse(); - this.ExistsTemporaryTableInDb(table2Name) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(table2Name).Should().BeFalse(); } [Theory] @@ -119,17 +111,9 @@ public async Task BuildDbCommand_ShouldSetCommandTimeout(bool useAsyncApi) { var timeout = Generate.Single(); - var (command, _) = await CallApi( - useAsyncApi, - "SELECT 1", - this.DatabaseAdapter, - this.Connection, - null, - timeout - ); + var (command, _) = await CallApi(useAsyncApi, "SELECT 1", this.DatabaseAdapter, this.Connection, null, timeout); - command.CommandTimeout - .Should().Be((int)timeout.TotalSeconds); + command.CommandTimeout.Should().Be((int)timeout.TotalSeconds); } [Theory] @@ -147,8 +131,7 @@ public async Task BuildDbCommand_ShouldSetCommandType(bool useAsyncApi) commandType: CommandType.StoredProcedure ); - command.CommandType - .Should().Be(CommandType.StoredProcedure); + command.CommandType.Should().Be(CommandType.StoredProcedure); } [Theory] @@ -156,11 +139,9 @@ public async Task BuildDbCommand_ShouldSetCommandType(bool useAsyncApi) [InlineData(true)] public async Task BuildDbCommand_ShouldSetConnection(bool useAsyncApi) { - var (command, _) = - await CallApi(useAsyncApi, "SELECT 1", this.DatabaseAdapter, this.Connection); + var (command, _) = await CallApi(useAsyncApi, "SELECT 1", this.DatabaseAdapter, this.Connection); - command.Connection - .Should().BeSameAs(this.Connection); + command.Connection.Should().BeSameAs(this.Connection); } [Theory] @@ -175,38 +156,35 @@ public async Task BuildDbCommand_ShouldSetParameters(bool useAsyncApi) var (command, _) = await CallApi( useAsyncApi, $""" - SELECT * - FROM Entity - WHERE Id = {Parameter(entityId)} AND - DateTimeValue = {Parameter(dateTimeValue)} AND - StringValue = {Parameter(stringValue)} - """, + SELECT * + FROM Entity + WHERE Id = {Parameter(entityId)} AND + DateTimeValue = {Parameter(dateTimeValue)} AND + StringValue = {Parameter(stringValue)} + """, this.DatabaseAdapter, this.Connection ); - command.CommandText - .Should().Be( + command + .CommandText.Should() + .Be( $""" - SELECT * - FROM Entity - WHERE Id = {P("EntityId")} AND - DateTimeValue = {P("DateTimeValue")} AND - StringValue = {P("StringValue")} - """ + SELECT * + FROM Entity + WHERE Id = {P("EntityId")} AND + DateTimeValue = {P("DateTimeValue")} AND + StringValue = {P("StringValue")} + """ ); - command.Parameters.Count - .Should().Be(3); + command.Parameters.Count.Should().Be(3); - command.Parameters["EntityId"].Value - .Should().Be(entityId); + command.Parameters["EntityId"].Value.Should().Be(entityId); - command.Parameters["DateTimeValue"].Value - .Should().Be(dateTimeValue); + command.Parameters["DateTimeValue"].Value.Should().Be(dateTimeValue); - command.Parameters["StringValue"].Value - .Should().Be(stringValue); + command.Parameters["StringValue"].Value.Should().Be(stringValue); } [Theory] @@ -216,16 +194,9 @@ public async Task BuildDbCommand_ShouldSetTransaction(bool useAsyncApi) { await using var transaction = await this.Connection.BeginTransactionAsync(); - var (command, _) = await CallApi( - useAsyncApi, - "SELECT 1", - this.DatabaseAdapter, - this.Connection, - transaction - ); + var (command, _) = await CallApi(useAsyncApi, "SELECT 1", this.DatabaseAdapter, this.Connection, transaction); - command.Transaction - .Should().BeSameAs(transaction); + command.Transaction.Should().BeSameAs(transaction); } [Theory] @@ -248,11 +219,13 @@ public async Task BuildDbCommand_ShouldUseCancellationToken(bool useAsyncApi) cancellationToken ); - var exception = (await Invoking(() => command.ExecuteNonQueryAsync(cancellationToken)) - .Should().ThrowAsync()).Subject.First(); + var exception = ( + await Invoking(() => command.ExecuteNonQueryAsync(cancellationToken)).Should().ThrowAsync() + ).Subject.First(); this.DatabaseAdapter.WasSqlStatementCancelledByCancellationToken(exception, cancellationToken) - .Should().BeTrue(); + .Should() + .BeTrue(); } private static Task<(DbCommand, DbCommandDisposer)> CallApi( diff --git a/tests/DbConnectionPlus.IntegrationTests/DbCommands/DbCommandDisposerTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbCommands/DbCommandDisposerTests.cs index 7a39e24..045f3ca 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbCommands/DbCommandDisposerTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbCommands/DbCommandDisposerTests.cs @@ -1,24 +1,14 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.DbCommands; -public sealed class - DbCommandDisposerTests_MySql : - DbCommandDisposerTests; +public sealed class DbCommandDisposerTests_MySql : DbCommandDisposerTests; -public sealed class - DbCommandDisposerTests_Oracle : - DbCommandDisposerTests; +public sealed class DbCommandDisposerTests_Oracle : DbCommandDisposerTests; -public sealed class - DbCommandDisposerTests_PostgreSql : - DbCommandDisposerTests; +public sealed class DbCommandDisposerTests_PostgreSql : DbCommandDisposerTests; -public sealed class - DbCommandDisposerTests_Sqlite : - DbCommandDisposerTests; +public sealed class DbCommandDisposerTests_Sqlite : DbCommandDisposerTests; -public sealed class - DbCommandDisposerTests_SqlServer : - DbCommandDisposerTests; +public sealed class DbCommandDisposerTests_SqlServer : DbCommandDisposerTests; public abstract class DbCommandDisposerTests : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() @@ -36,22 +26,17 @@ public void Dispose_AlreadyDisposed_ShouldNotAttemptToDropTemporaryTablesAgain() var (_, commandDisposer) = DbCommandBuilder.BuildDbCommand(statement, this.DatabaseAdapter, this.Connection); - this.ExistsTemporaryTableInDb(temporaryTables[0].Name) - .Should().BeTrue(); + this.ExistsTemporaryTableInDb(temporaryTables[0].Name).Should().BeTrue(); commandDisposer.Dispose(); - this.ExistsTemporaryTableInDb(temporaryTables[0].Name) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTables[0].Name).Should().BeFalse(); - Invoking(() => commandDisposer.Dispose()) - .Should().NotThrow(); + Invoking(() => commandDisposer.Dispose()).Should().NotThrow(); - Invoking(() => commandDisposer.Dispose()) - .Should().NotThrow(); + Invoking(() => commandDisposer.Dispose()).Should().NotThrow(); - Invoking(() => commandDisposer.Dispose()) - .Should().NotThrow(); + Invoking(() => commandDisposer.Dispose()).Should().NotThrow(); } [Fact] @@ -62,30 +47,25 @@ public void Dispose_ShouldDropTemporaryTables() var entityIds1 = Generate.Ids(); var entityIds2 = Generate.Ids(); - InterpolatedSqlStatement statement = - $""" - SELECT {Q("Value")} FROM {TemporaryTable(entityIds1)} - UNION - SELECT {Q("Value")} FROM {TemporaryTable(entityIds2)} - """; + InterpolatedSqlStatement statement = $""" + SELECT {Q("Value")} FROM {TemporaryTable(entityIds1)} + UNION + SELECT {Q("Value")} FROM {TemporaryTable(entityIds2)} + """; var temporaryTables = statement.TemporaryTables; var (_, commandDisposer) = DbCommandBuilder.BuildDbCommand(statement, this.DatabaseAdapter, this.Connection); - this.ExistsTemporaryTableInDb(temporaryTables[0].Name) - .Should().BeTrue(); + this.ExistsTemporaryTableInDb(temporaryTables[0].Name).Should().BeTrue(); - this.ExistsTemporaryTableInDb(temporaryTables[1].Name) - .Should().BeTrue(); + this.ExistsTemporaryTableInDb(temporaryTables[1].Name).Should().BeTrue(); commandDisposer.Dispose(); - this.ExistsTemporaryTableInDb(temporaryTables[0].Name) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTables[0].Name).Should().BeFalse(); - this.ExistsTemporaryTableInDb(temporaryTables[1].Name) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTables[1].Name).Should().BeFalse(); } [Fact] @@ -98,25 +78,23 @@ public async Task DisposeAsync_AlreadyDisposed_ShouldNotAttemptToDropTemporaryTa var temporaryTables = statement.TemporaryTables; - var (_, commandDisposer) = - await DbCommandBuilder.BuildDbCommandAsync(statement, this.DatabaseAdapter, this.Connection); + var (_, commandDisposer) = await DbCommandBuilder.BuildDbCommandAsync( + statement, + this.DatabaseAdapter, + this.Connection + ); - this.ExistsTemporaryTableInDb(temporaryTables[0].Name) - .Should().BeTrue(); + this.ExistsTemporaryTableInDb(temporaryTables[0].Name).Should().BeTrue(); await commandDisposer.DisposeAsync(); - this.ExistsTemporaryTableInDb(temporaryTables[0].Name) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTables[0].Name).Should().BeFalse(); - await Invoking(() => commandDisposer.DisposeAsync().AsTask()) - .Should().NotThrowAsync(); + await Invoking(() => commandDisposer.DisposeAsync().AsTask()).Should().NotThrowAsync(); - await Invoking(() => commandDisposer.DisposeAsync().AsTask()) - .Should().NotThrowAsync(); + await Invoking(() => commandDisposer.DisposeAsync().AsTask()).Should().NotThrowAsync(); - await Invoking(() => commandDisposer.DisposeAsync().AsTask()) - .Should().NotThrowAsync(); + await Invoking(() => commandDisposer.DisposeAsync().AsTask()).Should().NotThrowAsync(); } [Fact] @@ -127,24 +105,24 @@ public async Task DisposeAsync_ShouldDisposeTemporaryTables() var entityIds1 = Generate.Ids(); var entityIds2 = Generate.Ids(); - InterpolatedSqlStatement statement = - $""" - SELECT {Q("Value")} FROM {TemporaryTable(entityIds1)} - UNION - SELECT {Q("Value")} FROM {TemporaryTable(entityIds2)} - """; + InterpolatedSqlStatement statement = $""" + SELECT {Q("Value")} FROM {TemporaryTable(entityIds1)} + UNION + SELECT {Q("Value")} FROM {TemporaryTable(entityIds2)} + """; var temporaryTables = statement.TemporaryTables; - var (_, commandDisposer) = - await DbCommandBuilder.BuildDbCommandAsync(statement, this.DatabaseAdapter, this.Connection); + var (_, commandDisposer) = await DbCommandBuilder.BuildDbCommandAsync( + statement, + this.DatabaseAdapter, + this.Connection + ); - this.ExistsTemporaryTableInDb(temporaryTables[0].Name) - .Should().BeTrue(); + this.ExistsTemporaryTableInDb(temporaryTables[0].Name).Should().BeTrue(); await commandDisposer.DisposeAsync(); - this.ExistsTemporaryTableInDb(temporaryTables[0].Name) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTables[0].Name).Should().BeFalse(); } } diff --git a/tests/DbConnectionPlus.IntegrationTests/DbCommands/DbCommandHelperTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbCommands/DbCommandHelperTests.cs index a23ee73..f21f6fa 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbCommands/DbCommandHelperTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbCommands/DbCommandHelperTests.cs @@ -1,24 +1,14 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.DbCommands; -public sealed class - DbCommandHelperTests_MySql : - DbCommandHelperTests; +public sealed class DbCommandHelperTests_MySql : DbCommandHelperTests; -public sealed class - DbCommandHelperTests_Oracle : - DbCommandHelperTests; +public sealed class DbCommandHelperTests_Oracle : DbCommandHelperTests; -public sealed class - DbCommandHelperTests_PostgreSql : - DbCommandHelperTests; +public sealed class DbCommandHelperTests_PostgreSql : DbCommandHelperTests; -public sealed class - DbCommandHelperTests_Sqlite : - DbCommandHelperTests; +public sealed class DbCommandHelperTests_Sqlite : DbCommandHelperTests; -public sealed class - DbCommandHelperTests_SqlServer : - DbCommandHelperTests; +public sealed class DbCommandHelperTests_SqlServer : DbCommandHelperTests; public abstract class DbCommandHelperTests : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() @@ -34,17 +24,16 @@ public void RegisterDbCommandCancellation_CancellationToken_ShouldRegister() var command = this.Connection.CreateCommand(); - command.CommandText = - this.TestDatabaseProvider.DelayTwoSecondsStatement + $"DELETE FROM {Q("Entity")}"; + command.CommandText = this.TestDatabaseProvider.DelayTwoSecondsStatement + $"DELETE FROM {Q("Entity")}"; - using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(command, cancellationToken); + using var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation( + command, + cancellationToken + ); - Invoking(() => command.ExecuteNonQuery()) - .Should().Throw(); + Invoking(() => command.ExecuteNonQuery()).Should().Throw(); - this.ExistsEntityInDb(entity) - .Should().BeTrue(); + this.ExistsEntityInDb(entity).Should().BeTrue(); } [Fact] @@ -56,16 +45,15 @@ public void RegisterDbCommandCancellation_NoneCancellationToken_ShouldNotRegiste var command = this.Connection.CreateCommand(); - command.CommandText = - this.TestDatabaseProvider.DelayTwoSecondsStatement + $"DELETE FROM {Q("Entity")}"; + command.CommandText = this.TestDatabaseProvider.DelayTwoSecondsStatement + $"DELETE FROM {Q("Entity")}"; - using var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(command, CancellationToken.None); + using var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation( + command, + CancellationToken.None + ); - command.ExecuteNonQuery() - .Should().Be(1); + command.ExecuteNonQuery().Should().Be(1); - this.ExistsEntityInDb(entity) - .Should().BeFalse(); + this.ExistsEntityInDb(entity).Should().BeFalse(); } } diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteNonQueryTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteNonQueryTests.cs index f93e6a1..49e546f 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteNonQueryTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteNonQueryTests.cs @@ -2,36 +2,29 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests; -public sealed class - DbConnectionExtensions_ExecuteNonQueryTests_MySql : - DbConnectionExtensions_ExecuteNonQueryTests; +public sealed class DbConnectionExtensions_ExecuteNonQueryTests_MySql + : DbConnectionExtensions_ExecuteNonQueryTests; -public sealed class - DbConnectionExtensions_ExecuteNonQueryTests_Oracle : - DbConnectionExtensions_ExecuteNonQueryTests; +public sealed class DbConnectionExtensions_ExecuteNonQueryTests_Oracle + : DbConnectionExtensions_ExecuteNonQueryTests; -public sealed class - DbConnectionExtensions_ExecuteNonQueryTests_PostgreSql : - DbConnectionExtensions_ExecuteNonQueryTests; +public sealed class DbConnectionExtensions_ExecuteNonQueryTests_PostgreSql + : DbConnectionExtensions_ExecuteNonQueryTests; -public sealed class - DbConnectionExtensions_ExecuteNonQueryTests_Sqlite : - DbConnectionExtensions_ExecuteNonQueryTests; +public sealed class DbConnectionExtensions_ExecuteNonQueryTests_Sqlite + : DbConnectionExtensions_ExecuteNonQueryTests; -public sealed class - DbConnectionExtensions_ExecuteNonQueryTests_SqlServer : - DbConnectionExtensions_ExecuteNonQueryTests; +public sealed class DbConnectionExtensions_ExecuteNonQueryTests_SqlServer + : DbConnectionExtensions_ExecuteNonQueryTests; -public abstract class - DbConnectionExtensions_ExecuteNonQueryTests : IntegrationTestsBase +public abstract class DbConnectionExtensions_ExecuteNonQueryTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteNonQuery_CancellationToken_ShouldCancelOperationIfCancellationIsRequested( - bool useAsyncApi - ) + public async Task ExecuteNonQuery_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -41,19 +34,20 @@ bool useAsyncApi this.DelayNextDbCommand = true; - await Invoking(() => CallApi( + await Invoking(() => + CallApi( useAsyncApi, this.Connection, $"DELETE FROM {Q("Entity")}", cancellationToken: cancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); // Since the operation was cancelled, the entity should still exist. - this.ExistsEntityInDb(entity) - .Should().BeTrue(); + this.ExistsEntityInDb(entity).Should().BeTrue(); } [Theory] @@ -73,8 +67,7 @@ await CallApi( cancellationToken: TestContext.Current.CancellationToken ); - this.ExistsEntityInDb(entity) - .Should().BeFalse(); + this.ExistsEntityInDb(entity).Should().BeFalse(); } [Theory] @@ -89,39 +82,39 @@ bool useAsyncApi var entities = this.CreateEntitiesInDb(5); var entitiesToDelete = entities.Take(2).ToList(); - InterpolatedSqlStatement statement = - $""" - DELETE FROM {Q("Entity")} - WHERE EXISTS ( - SELECT 1 - FROM {TemporaryTable(entitiesToDelete)} TEntitiesToDelete - WHERE {Q("Entity")}.{Q("Id")} = TEntitiesToDelete.{Q("Id")} AND - {Q("Entity")}.{Q("StringValue")} = TEntitiesToDelete.{Q("StringValue")} AND - {Q("Entity")}.{Q("Int32Value")} = TEntitiesToDelete.{Q("Int32Value")} - ) - """; + InterpolatedSqlStatement statement = $""" + DELETE FROM {Q("Entity")} + WHERE EXISTS ( + SELECT 1 + FROM {TemporaryTable(entitiesToDelete)} TEntitiesToDelete + WHERE {Q("Entity")}.{Q("Id")} = TEntitiesToDelete.{Q("Id")} AND + {Q("Entity")}.{Q("StringValue")} = TEntitiesToDelete.{Q("StringValue")} AND + {Q("Entity")}.{Q("Int32Value")} = TEntitiesToDelete.{Q("Int32Value")} + ) + """; var temporaryTableName = statement.TemporaryTables[0].Name; - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, statement, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(entitiesToDelete.Count); + ) + ) + .Should() + .Be(entitiesToDelete.Count); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - ExecuteNonQuery_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - bool useAsyncApi - ) + public async Task ExecuteNonQuery_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -132,28 +125,26 @@ await CallApi( useAsyncApi, this.Connection, $""" - DELETE FROM {Q("Entity")} - WHERE EXISTS ( - SELECT 1 - FROM {TemporaryTable(entitiesToDelete)} TEntitiesToDelete - WHERE {Q("Entity")}.{Q("Id")} = TEntitiesToDelete.{Q("Id")} AND - {Q("Entity")}.{Q("StringValue")} = TEntitiesToDelete.{Q("StringValue")} AND - {Q("Entity")}.{Q("Int32Value")} = TEntitiesToDelete.{Q("Int32Value")} - ) - """, + DELETE FROM {Q("Entity")} + WHERE EXISTS ( + SELECT 1 + FROM {TemporaryTable(entitiesToDelete)} TEntitiesToDelete + WHERE {Q("Entity")}.{Q("Id")} = TEntitiesToDelete.{Q("Id")} AND + {Q("Entity")}.{Q("StringValue")} = TEntitiesToDelete.{Q("StringValue")} AND + {Q("Entity")}.{Q("Int32Value")} = TEntitiesToDelete.{Q("Int32Value")} + ) + """, cancellationToken: TestContext.Current.CancellationToken ); foreach (var entity in entitiesToDelete) { - this.ExistsEntityInDb(entity) - .Should().BeFalse(); + this.ExistsEntityInDb(entity).Should().BeFalse(); } foreach (var entity in entities.Except(entitiesToDelete)) { - this.ExistsEntityInDb(entity) - .Should().BeTrue(); + this.ExistsEntityInDb(entity).Should().BeTrue(); } } @@ -171,8 +162,7 @@ await CallApi( cancellationToken: TestContext.Current.CancellationToken ); - this.ExistsEntityInDb(entity) - .Should().BeFalse(); + this.ExistsEntityInDb(entity).Should().BeFalse(); } [Theory] @@ -194,8 +184,7 @@ await CallApi( cancellationToken: TestContext.Current.CancellationToken ); - this.ExistsEntityInDb(entity) - .Should().BeFalse(); + this.ExistsEntityInDb(entity).Should().BeFalse(); } [Theory] @@ -211,33 +200,33 @@ bool useAsyncApi var entitiesToDelete = entities.Take(2).ToList(); var idsOfEntitiesToDelete = entitiesToDelete.ConvertAll(a => a.Id); - InterpolatedSqlStatement statement = - $""" - DELETE FROM {Q("Entity")} - WHERE {Q("Id")} IN (SELECT {Q("Value")} FROM {TemporaryTable(idsOfEntitiesToDelete)}) - """; + InterpolatedSqlStatement statement = $""" + DELETE FROM {Q("Entity")} + WHERE {Q("Id")} IN (SELECT {Q("Value")} FROM {TemporaryTable(idsOfEntitiesToDelete)}) + """; var temporaryTableName = statement.TemporaryTables[0].Name; - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, statement, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(idsOfEntitiesToDelete.Count); + ) + ) + .Should() + .Be(idsOfEntitiesToDelete.Count); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - ExecuteNonQuery_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - bool useAsyncApi - ) + public async Task ExecuteNonQuery_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -249,22 +238,20 @@ await CallApi( useAsyncApi, this.Connection, $""" - DELETE FROM {Q("Entity")} - WHERE {Q("Id")} IN (SELECT {Q("Value")} FROM {TemporaryTable(idsOfEntitiesToDelete)}) - """, + DELETE FROM {Q("Entity")} + WHERE {Q("Id")} IN (SELECT {Q("Value")} FROM {TemporaryTable(idsOfEntitiesToDelete)}) + """, cancellationToken: TestContext.Current.CancellationToken ); foreach (var entity in entitiesToDelete) { - this.ExistsEntityInDb(entity) - .Should().BeFalse(); + this.ExistsEntityInDb(entity).Should().BeFalse(); } foreach (var entity in entities.Except(entitiesToDelete)) { - this.ExistsEntityInDb(entity) - .Should().BeTrue(); + this.ExistsEntityInDb(entity).Should().BeTrue(); } } @@ -275,21 +262,27 @@ public async Task ExecuteNonQuery_ShouldReturnNumberOfAffectedRows(bool useAsync { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"DELETE FROM {Q("Entity")} WHERE {Q("Id")} = {Parameter(entity.Id)}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(1); + ) + ) + .Should() + .Be(1); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"DELETE FROM {Q("Entity")} WHERE {Q("Id")} = {Parameter(entity.Id)}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(0); + ) + ) + .Should() + .Be(0); } [Theory] @@ -309,14 +302,12 @@ await CallApi( cancellationToken: TestContext.Current.CancellationToken ); - this.ExistsEntityInDb(entity, transaction) - .Should().BeFalse(); + this.ExistsEntityInDb(entity, transaction).Should().BeFalse(); await transaction.RollbackAsync(); } - this.ExistsEntityInDb(entity) - .Should().BeTrue(); + this.ExistsEntityInDb(entity).Should().BeTrue(); } private static Task CallApi( diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteReaderTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteReaderTests.cs index 354338f..e2dbf5d 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteReaderTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteReaderTests.cs @@ -2,36 +2,29 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests; -public sealed class - DbConnectionExtensions_ExecuteReaderTests_MySql : - DbConnectionExtensions_ExecuteReaderTests; +public sealed class DbConnectionExtensions_ExecuteReaderTests_MySql + : DbConnectionExtensions_ExecuteReaderTests; -public sealed class - DbConnectionExtensions_ExecuteReaderTests_Oracle : - DbConnectionExtensions_ExecuteReaderTests; +public sealed class DbConnectionExtensions_ExecuteReaderTests_Oracle + : DbConnectionExtensions_ExecuteReaderTests; -public sealed class - DbConnectionExtensions_ExecuteReaderTests_PostgreSql : - DbConnectionExtensions_ExecuteReaderTests; +public sealed class DbConnectionExtensions_ExecuteReaderTests_PostgreSql + : DbConnectionExtensions_ExecuteReaderTests; -public sealed class - DbConnectionExtensions_ExecuteReaderTests_Sqlite : - DbConnectionExtensions_ExecuteReaderTests; +public sealed class DbConnectionExtensions_ExecuteReaderTests_Sqlite + : DbConnectionExtensions_ExecuteReaderTests; -public sealed class - DbConnectionExtensions_ExecuteReaderTests_SqlServer : - DbConnectionExtensions_ExecuteReaderTests; +public sealed class DbConnectionExtensions_ExecuteReaderTests_SqlServer + : DbConnectionExtensions_ExecuteReaderTests; -public abstract class - DbConnectionExtensions_ExecuteReaderTests : IntegrationTestsBase +public abstract class DbConnectionExtensions_ExecuteReaderTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteReader_CancellationToken_ShouldCancelOperationIfCancellationIsRequested( - bool useAsyncApi - ) + public async Task ExecuteReader_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -40,16 +33,16 @@ bool useAsyncApi this.DelayNextDbCommand = true; await Invoking(async () => - { - await using var reader = await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("Entity")}", - cancellationToken: cancellationToken - ); - } - ) - .Should().ThrowAsync() + { + await using var reader = await CallApi( + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("Entity")}", + cancellationToken: cancellationToken + ); + }) + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); } @@ -68,8 +61,7 @@ public async Task ExecuteReader_CommandBehavior_ShouldUseCommandBehavior(bool us await reader.DisposeAsync(); - this.Connection.State - .Should().Be(ConnectionState.Closed); + this.Connection.State.Should().Be(ConnectionState.Closed); } [Theory] @@ -91,31 +83,29 @@ public async Task ExecuteReader_CommandType_ShouldUseCommandType(bool useAsyncAp foreach (var entity in entities) { - (await reader.ReadAsync(TestContext.Current.CancellationToken)) - .Should().BeTrue(); + (await reader.ReadAsync(TestContext.Current.CancellationToken)).Should().BeTrue(); - reader.GetInt64(0) - .Should().Be(entity.Id); + reader.GetInt64(0).Should().Be(entity.Id); - reader.GetString(1) - .Should().Be(entity.StringValue); + reader.GetString(1).Should().Be(entity.StringValue); } } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - ExecuteReader_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterDataReaderDisposal(bool useAsyncApi) + public async Task ExecuteReader_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterDataReaderDisposal( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entities = Generate.Multiple(); InterpolatedSqlStatement statement = $""" - SELECT {Q("Id")} - FROM {TemporaryTable(entities)} - """; + SELECT {Q("Id")} + FROM {TemporaryTable(entities)} + """; var temporaryTableName = statement.TemporaryTables[0].Name; var reader = await CallApi( @@ -127,23 +117,20 @@ public async Task if (this.TestDatabaseProvider.SupportsCommandExecutionWhileDataReaderIsOpen) { - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeTrue(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeTrue(); } await reader.DisposeAsync(); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - ExecuteReader_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - bool useAsyncApi - ) + public async Task ExecuteReader_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -153,25 +140,21 @@ bool useAsyncApi useAsyncApi, this.Connection, $""" - SELECT {Q("Id")}, {Q("StringValue")}, {Q("DecimalValue")} - FROM {TemporaryTable(entities)} - """, + SELECT {Q("Id")}, {Q("StringValue")}, {Q("DecimalValue")} + FROM {TemporaryTable(entities)} + """, cancellationToken: TestContext.Current.CancellationToken ); foreach (var entity in entities) { - (await reader.ReadAsync(TestContext.Current.CancellationToken)) - .Should().BeTrue(); + (await reader.ReadAsync(TestContext.Current.CancellationToken)).Should().BeTrue(); - reader.GetInt64(0) - .Should().Be(entity.Id); + reader.GetInt64(0).Should().Be(entity.Id); - reader.GetString(1) - .Should().Be(entity.StringValue); + reader.GetString(1).Should().Be(entity.StringValue); - reader.GetDecimal(2) - .Should().Be(entity.DecimalValue); + reader.GetDecimal(2).Should().Be(entity.DecimalValue); } } @@ -189,11 +172,9 @@ public async Task ExecuteReader_InterpolatedParameter_ShouldPassInterpolatedPara cancellationToken: TestContext.Current.CancellationToken ); - (await reader.ReadAsync(TestContext.Current.CancellationToken)) - .Should().BeTrue(); + (await reader.ReadAsync(TestContext.Current.CancellationToken)).Should().BeTrue(); - reader.GetString(0) - .Should().Be(entity.StringValue); + reader.GetString(0).Should().Be(entity.StringValue); } [Theory] @@ -215,11 +196,9 @@ public async Task ExecuteReader_Parameter_ShouldPassParameter(bool useAsyncApi) cancellationToken: TestContext.Current.CancellationToken ); - (await reader.ReadAsync(TestContext.Current.CancellationToken)) - .Should().BeTrue(); + (await reader.ReadAsync(TestContext.Current.CancellationToken)).Should().BeTrue(); - reader.GetString(0) - .Should().Be(entity.StringValue); + reader.GetString(0).Should().Be(entity.StringValue); } [Theory] @@ -246,23 +225,20 @@ bool useAsyncApi if (this.TestDatabaseProvider.SupportsCommandExecutionWhileDataReaderIsOpen) { - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeTrue(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeTrue(); } await reader.DisposeAsync(); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - ExecuteReader_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - bool useAsyncApi - ) + public async Task ExecuteReader_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -277,11 +253,9 @@ bool useAsyncApi foreach (var entityId in entityIds) { - (await reader.ReadAsync(TestContext.Current.CancellationToken)) - .Should().BeTrue(); + (await reader.ReadAsync(TestContext.Current.CancellationToken)).Should().BeTrue(); - reader.GetInt64(0) - .Should().Be(entityId); + reader.GetInt64(0).Should().Be(entityId); } } @@ -301,18 +275,14 @@ public async Task ExecuteReader_ShouldReturnDataReaderForQueryResult(bool useAsy foreach (var entity in entities) { - (await reader.ReadAsync(TestContext.Current.CancellationToken)) - .Should().BeTrue(); + (await reader.ReadAsync(TestContext.Current.CancellationToken)).Should().BeTrue(); - reader.GetInt64(0) - .Should().Be(entity.Id); + reader.GetInt64(0).Should().Be(entity.Id); - reader.GetString(1) - .Should().Be(entity.StringValue); + reader.GetString(1).Should().Be(entity.StringValue); } - (await reader.ReadAsync(TestContext.Current.CancellationToken)) - .Should().BeFalse(); + (await reader.ReadAsync(TestContext.Current.CancellationToken)).Should().BeFalse(); } [Theory] @@ -332,19 +302,15 @@ public async Task ExecuteReader_Transaction_ShouldUseTransaction(bool useAsyncAp cancellationToken: TestContext.Current.CancellationToken ); - reader.HasRows - .Should().BeTrue(); + reader.HasRows.Should().BeTrue(); foreach (var entity in entities) { - (await reader.ReadAsync(TestContext.Current.CancellationToken)) - .Should().BeTrue(); + (await reader.ReadAsync(TestContext.Current.CancellationToken)).Should().BeTrue(); - reader.GetInt64(0) - .Should().Be(entity.Id); + reader.GetInt64(0).Should().Be(entity.Id); - reader.GetString(1) - .Should().Be(entity.StringValue); + reader.GetString(1).Should().Be(entity.StringValue); } await reader.DisposeAsync(); @@ -352,13 +318,16 @@ public async Task ExecuteReader_Transaction_ShouldUseTransaction(bool useAsyncAp await transaction.RollbackAsync(); } - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("Id")}, {Q("StringValue")} FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )).HasRows - .Should().BeFalse(); + ) + ) + .HasRows.Should() + .BeFalse(); } private static Task CallApi( diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteScalarTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteScalarTests.cs index 93e907f..c3735f8 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteScalarTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExecuteScalarTests.cs @@ -2,36 +2,29 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests; -public sealed class - DbConnectionExtensions_ExecuteScalarTests_MySql : - DbConnectionExtensions_ExecuteScalarTests; +public sealed class DbConnectionExtensions_ExecuteScalarTests_MySql + : DbConnectionExtensions_ExecuteScalarTests; -public sealed class - DbConnectionExtensions_ExecuteScalarTests_Oracle : - DbConnectionExtensions_ExecuteScalarTests; +public sealed class DbConnectionExtensions_ExecuteScalarTests_Oracle + : DbConnectionExtensions_ExecuteScalarTests; -public sealed class - DbConnectionExtensions_ExecuteScalarTests_PostgreSql : - DbConnectionExtensions_ExecuteScalarTests; +public sealed class DbConnectionExtensions_ExecuteScalarTests_PostgreSql + : DbConnectionExtensions_ExecuteScalarTests; -public sealed class - DbConnectionExtensions_ExecuteScalarTests_Sqlite : - DbConnectionExtensions_ExecuteScalarTests; +public sealed class DbConnectionExtensions_ExecuteScalarTests_Sqlite + : DbConnectionExtensions_ExecuteScalarTests; -public sealed class - DbConnectionExtensions_ExecuteScalarTests_SqlServer : - DbConnectionExtensions_ExecuteScalarTests; +public sealed class DbConnectionExtensions_ExecuteScalarTests_SqlServer + : DbConnectionExtensions_ExecuteScalarTests; -public abstract class - DbConnectionExtensions_ExecuteScalarTests : IntegrationTestsBase +public abstract class DbConnectionExtensions_ExecuteScalarTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteScalar_CancellationToken_ShouldCancelOperationIfCancellationIsRequested( - bool useAsyncApi - ) + public async Task ExecuteScalar_CancellationToken_ShouldCancelOperationIfCancellationIsRequested(bool useAsyncApi) { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -40,14 +33,10 @@ bool useAsyncApi this.DelayNextDbCommand = true; await Invoking(() => - CallApi( - useAsyncApi, - this.Connection, - "SELECT 1", - cancellationToken: cancellationToken - ) + CallApi(useAsyncApi, this.Connection, "SELECT 1", cancellationToken: cancellationToken) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); } @@ -63,10 +52,11 @@ public Task ExecuteScalar_ColumnValueCannotBeConvertedToTargetType_ShouldThrow(b cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column of the first row in the result set returned by the SQL statement contains the " + - $"value 'A' ({typeof(string)}), which could not be converted to the type {typeof(int)}.*" + "The first column of the first row in the result set returned by the SQL statement contains the " + + $"value 'A' ({typeof(string)}), which could not be converted to the type {typeof(int)}.*" ); [Theory] @@ -78,14 +68,17 @@ public async Task ExecuteScalar_CommandType_ShouldUseCommandType(bool useAsyncAp var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, "GetFirstEntityId", commandType: CommandType.StoredProcedure, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(entity.Id); + ) + ) + .Should() + .Be(entity.Id); } [Theory] @@ -100,46 +93,48 @@ bool useAsyncApi var entities = Generate.Multiple(1); InterpolatedSqlStatement statement = $""" - SELECT {Q("StringValue")} - FROM {TemporaryTable(entities)} - """; + SELECT {Q("StringValue")} + FROM {TemporaryTable(entities)} + """; var temporaryTableName = statement.TemporaryTables[0].Name; - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, statement, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(entities[0].StringValue); + ) + ) + .Should() + .Be(entities[0].StringValue); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - ExecuteScalar_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - bool useAsyncApi - ) + public async Task ExecuteScalar_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entities = Generate.Multiple(1); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $""" - SELECT {Q("StringValue")} - FROM {TemporaryTable(entities)} - """, + SELECT {Q("StringValue")} + FROM {TemporaryTable(entities)} + """, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(entities[0].StringValue); + ) + ).Should().Be(entities[0].StringValue); } [Theory] @@ -149,13 +144,16 @@ public async Task ExecuteScalar_InterpolatedParameter_ShouldPassInterpolatedPara { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("StringValue")} FROM {Q("Entity")} WHERE {Q("Id")} = {Parameter(entity.Id)}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(entity.StringValue); + ) + ) + .Should() + .Be(entity.StringValue); } [Theory] @@ -163,21 +161,27 @@ public async Task ExecuteScalar_InterpolatedParameter_ShouldPassInterpolatedPara [InlineData(true)] public async Task ExecuteScalar_NoResultSet_ShouldReturnDefault(bool useAsyncApi) { - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, "SELECT 1 WHERE 0 = 1", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeNull(); + ) + ) + .Should() + .BeNull(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, "SELECT 1 WHERE 0 = 1", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(0); + ) + ) + .Should() + .Be(0); } [Theory] @@ -192,21 +196,22 @@ public async Task ExecuteScalar_Parameter_ShouldPassParameter(bool useAsyncApi) ("Id", entity.Id) ); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, statement, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(entity.StringValue); + ) + ) + .Should() + .Be(entity.StringValue); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteScalar_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution( - bool useAsyncApi - ) + public async Task ExecuteScalar_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -216,37 +221,41 @@ bool useAsyncApi var temporaryTableName = statement.TemporaryTables[0].Name; - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, statement, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(entityIds[0]); + ) + ) + .Should() + .Be(entityIds[0]); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - ExecuteScalar_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - bool useAsyncApi - ) + public async Task ExecuteScalar_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entityIds = Generate.Ids(1); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("Value")} FROM {TemporaryTable(entityIds)}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(entityIds[0]); + ) + ) + .Should() + .Be(entityIds[0]); } [Theory] @@ -258,30 +267,30 @@ public async Task ExecuteScalar_ShouldSupportDateTimeOffsetValues(bool useAsyncA var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $""" - SELECT {Q("DateTimeOffsetValue")} - FROM {Q("EntityWithDateTimeOffset")} - """, + SELECT {Q("DateTimeOffsetValue")} + FROM {Q("EntityWithDateTimeOffset")} + """, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(entity.DateTimeOffsetValue); + ) + ).Should().Be(entity.DateTimeOffsetValue); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteScalar_TargetTypeIsChar_ColumnValueIsStringWithLengthNotOne_ShouldThrow( - bool useAsyncApi - ) + public async Task ExecuteScalar_TargetTypeIsChar_ColumnValueIsStringWithLengthNotOne_ShouldThrow(bool useAsyncApi) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) { // Oracle doesn't allow to return an empty string, because it treats empty strings as NULLs. - (await Invoking(() => + ( + await Invoking(() => CallApi( useAsyncApi, this.Connection, @@ -289,20 +298,23 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column of the first row in the result set returned by the SQL statement contains " + - $"the value '' ({typeof(string)}), which could not be converted to the type {typeof(char)}. " + - "See inner exception for details.*" - )) + "The first column of the first row in the result set returned by the SQL statement contains " + + $"the value '' ({typeof(string)}), which could not be converted to the type {typeof(char)}. " + + "See inner exception for details.*" + ) + ) .WithInnerException() .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } - (await Invoking(() => + ( + await Invoking(() => CallApi( useAsyncApi, this.Connection, @@ -310,52 +322,59 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column of the first row in the result set returned by the SQL statement contains the " + - $"value 'ab' ({typeof(string)}), which could not be converted to the type {typeof(char)}. See " + - "inner exception for details.*" - )) + "The first column of the first row in the result set returned by the SQL statement contains the " + + $"value 'ab' ({typeof(string)}), which could not be converted to the type {typeof(char)}. See " + + "inner exception for details.*" + ) + ) .WithInnerException() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - ExecuteScalar_TargetTypeIsChar_ColumnValueIsStringWithLengthOne_ShouldGetFirstCharacter(bool useAsyncApi) + public async Task ExecuteScalar_TargetTypeIsChar_ColumnValueIsStringWithLengthOne_ShouldGetFirstCharacter( + bool useAsyncApi + ) { var character = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT '{character}'", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(character); + ) + ) + .Should() + .Be(character); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task ExecuteScalar_TargetTypeIsEnum_ColumnValueIsInteger_ShouldConvertIntegerToEnum( - bool useAsyncApi - ) + public async Task ExecuteScalar_TargetTypeIsEnum_ColumnValueIsInteger_ShouldConvertIntegerToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT {(int)enumValue}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(enumValue); + ) + ) + .Should() + .Be(enumValue); } [Theory] @@ -370,10 +389,11 @@ public Task ExecuteScalar_TargetTypeIsEnum_ColumnValueIsInvalidInteger_ShouldThr cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column of the first row in the result set returned by the SQL statement contains the " + - $"value '999*' (System.*), which could not be converted to the type {typeof(TestEnum)}.*" + "The first column of the first row in the result set returned by the SQL statement contains the " + + $"value '999*' (System.*), which could not be converted to the type {typeof(TestEnum)}.*" ); [Theory] @@ -388,11 +408,12 @@ public Task ExecuteScalar_TargetTypeIsEnum_ColumnValueIsInvalidString_ShouldThro cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column of the first row in the result set returned by the SQL statement contains the " + - $"value 'NonExistent' ({typeof(string)}), which could not be converted to the type " + - $"{typeof(TestEnum)}.*" + "The first column of the first row in the result set returned by the SQL statement contains the " + + $"value 'NonExistent' ({typeof(string)}), which could not be converted to the type " + + $"{typeof(TestEnum)}.*" ); [Theory] @@ -402,13 +423,16 @@ public async Task ExecuteScalar_TargetTypeIsEnum_ColumnValueIsString_ShouldConve { var enumValue = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT '{enumValue}'", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(enumValue); + ) + ) + .Should() + .Be(enumValue); } [Theory] @@ -423,23 +447,27 @@ public Task ExecuteScalar_TargetTypeIsNonNullable_ColumnValueIsNull_ShouldThrow( cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column of the first row in the result set returned by the SQL statement contains a NULL " + - $"value, which could not be converted to the type {typeof(int)}.*" + "The first column of the first row in the result set returned by the SQL statement contains a NULL " + + $"value, which could not be converted to the type {typeof(int)}.*" ); [Theory] [InlineData(false)] [InlineData(true)] public async Task ExecuteScalar_TargetTypeIsNullable_ColumnValueIsNull_ShouldReturnNull(bool useAsyncApi) => - (await CallApi( - useAsyncApi, - this.Connection, - "SELECT NULL", - cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeNull(); + ( + await CallApi( + useAsyncApi, + this.Connection, + "SELECT NULL", + cancellationToken: TestContext.Current.CancellationToken + ) + ) + .Should() + .BeNull(); [Theory] [InlineData(false)] @@ -450,25 +478,31 @@ public async Task ExecuteScalar_Transaction_ShouldUseTransaction(bool useAsyncAp { var entity = this.CreateEntityInDb(transaction); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("StringValue")} FROM {Q("Entity")}", transaction, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(entity.StringValue); + ) + ) + .Should() + .Be(entity.StringValue); await transaction.RollbackAsync(); } - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("StringValue")} FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeNull(); + ) + ) + .Should() + .BeNull(); } private static Task CallApi( diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExistsTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExistsTests.cs index 882ad42..2c744a1 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExistsTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ExistsTests.cs @@ -2,28 +2,23 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests; -public sealed class - DbConnectionExtensions_ExistsTests_MySql : - DbConnectionExtensions_ExistsTests; +public sealed class DbConnectionExtensions_ExistsTests_MySql + : DbConnectionExtensions_ExistsTests; -public sealed class - DbConnectionExtensions_ExistsTests_Oracle : - DbConnectionExtensions_ExistsTests; +public sealed class DbConnectionExtensions_ExistsTests_Oracle + : DbConnectionExtensions_ExistsTests; -public sealed class - DbConnectionExtensions_ExistsTests_PostgreSql : - DbConnectionExtensions_ExistsTests; +public sealed class DbConnectionExtensions_ExistsTests_PostgreSql + : DbConnectionExtensions_ExistsTests; -public sealed class - DbConnectionExtensions_ExistsTests_Sqlite : - DbConnectionExtensions_ExistsTests; +public sealed class DbConnectionExtensions_ExistsTests_Sqlite + : DbConnectionExtensions_ExistsTests; -public sealed class - DbConnectionExtensions_ExistsTests_SqlServer : - DbConnectionExtensions_ExistsTests; +public sealed class DbConnectionExtensions_ExistsTests_SqlServer + : DbConnectionExtensions_ExistsTests; -public abstract class - DbConnectionExtensions_ExistsTests : IntegrationTestsBase +public abstract class DbConnectionExtensions_ExistsTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { [Theory] @@ -38,7 +33,8 @@ public async Task Exists_CancellationToken_ShouldCancelOperationIfCancellationIs this.DelayNextDbCommand = true; await Invoking(() => CallApi(useAsyncApi, this.Connection, "SELECT 1", cancellationToken: cancellationToken)) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); } @@ -51,14 +47,17 @@ public async Task Exists_CommandType_ShouldUseCommandType(bool useAsyncApi) this.CreateEntitiesInDb(1); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, "GetFirstEntityId", commandType: CommandType.StoredProcedure, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeTrue(); + ) + ) + .Should() + .BeTrue(); } [Theory] @@ -71,48 +70,50 @@ public async Task Exists_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAf var entities = Generate.Multiple(1); InterpolatedSqlStatement statement = $""" - SELECT 1 - FROM {TemporaryTable(entities)} - WHERE {Q("Id")} = {Parameter(entities[0].Id)} - """; + SELECT 1 + FROM {TemporaryTable(entities)} + WHERE {Q("Id")} = {Parameter(entities[0].Id)} + """; var temporaryTableName = statement.TemporaryTables[0].Name; - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, statement, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeTrue(); + ) + ) + .Should() + .BeTrue(); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - Exists_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - bool useAsyncApi - ) + public async Task Exists_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entities = Generate.Multiple(1); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $""" - SELECT 1 - FROM {TemporaryTable(entities)} - WHERE {Q("Id")} = {Parameter(entities[0].Id)} - """, + SELECT 1 + FROM {TemporaryTable(entities)} + WHERE {Q("Id")} = {Parameter(entities[0].Id)} + """, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeTrue(); + ) + ).Should().BeTrue(); } [Theory] @@ -122,13 +123,16 @@ public async Task Exists_InterpolatedParameter_ShouldPassInterpolatedParameter(b { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT 1 FROM {Q("Entity")} WHERE {Q("Id")} = {Parameter(entity.Id)}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeTrue(); + ) + ) + .Should() + .BeTrue(); } [Theory] @@ -143,13 +147,16 @@ public async Task Exists_Parameter_ShouldPassParameter(bool useAsyncApi) ("Id", entity.Id) ); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, statement, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeTrue(); + ) + ) + .Should() + .BeTrue(); } [Theory] @@ -166,16 +173,18 @@ public async Task Exists_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfte var temporaryTableName = statement.TemporaryTables[0].Name; - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, statement, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeTrue(); + ) + ) + .Should() + .BeTrue(); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] @@ -189,13 +198,16 @@ bool useAsyncApi var entityIds = Generate.Ids(2); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT 1 FROM {TemporaryTable(entityIds)} WHERE {Q("Value")} = {Parameter(entityIds[0])}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeTrue(); + ) + ) + .Should() + .BeTrue(); } [Theory] @@ -205,21 +217,27 @@ public async Task Exists_ShouldReturnBooleanIndicatingWhetherQueryReturnedAtLeas { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT 1 FROM {Q("Entity")} WHERE {Q("Id")} = {Parameter(entity.Id)}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeTrue(); + ) + ) + .Should() + .BeTrue(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT 1 FROM {Q("Entity")} WHERE {Q("Id")} = -1", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeFalse(); + ) + ) + .Should() + .BeFalse(); } [Theory] @@ -231,25 +249,31 @@ public async Task Exists_Transaction_ShouldUseTransaction(bool useAsyncApi) { var entity = this.CreateEntityInDb(transaction); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT 1 FROM {Q("Entity")} WHERE {Q("Id")} = {Parameter(entity.Id)}", transaction, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeTrue(); + ) + ) + .Should() + .BeTrue(); await transaction.RollbackAsync(); } - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT 1 FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeFalse(); + ) + ) + .Should() + .BeFalse(); } private static Task CallApi( @@ -264,13 +288,7 @@ private static Task CallApi( { if (useAsyncApi) { - return connection.ExistsAsync( - statement, - transaction, - commandTimeout, - commandType, - cancellationToken - ); + return connection.ExistsAsync(statement, transaction, commandTimeout, commandType, cancellationToken); } try diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ParameterTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ParameterTests.cs index a288227..67afb9c 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ParameterTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.ParameterTests.cs @@ -1,27 +1,22 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests; -public sealed class - DbConnectionExtensions_ParameterTests_MySql : - DbConnectionExtensions_ParameterTests; +public sealed class DbConnectionExtensions_ParameterTests_MySql + : DbConnectionExtensions_ParameterTests; -public sealed class - DbConnectionExtensions_ParameterTests_Oracle : - DbConnectionExtensions_ParameterTests; +public sealed class DbConnectionExtensions_ParameterTests_Oracle + : DbConnectionExtensions_ParameterTests; -public sealed class - DbConnectionExtensions_ParameterTests_PostgreSql : - DbConnectionExtensions_ParameterTests; +public sealed class DbConnectionExtensions_ParameterTests_PostgreSql + : DbConnectionExtensions_ParameterTests; -public sealed class - DbConnectionExtensions_ParameterTests_Sqlite : - DbConnectionExtensions_ParameterTests; +public sealed class DbConnectionExtensions_ParameterTests_Sqlite + : DbConnectionExtensions_ParameterTests; -public sealed class - DbConnectionExtensions_ParameterTests_SqlServer : - DbConnectionExtensions_ParameterTests; +public sealed class DbConnectionExtensions_ParameterTests_SqlServer + : DbConnectionExtensions_ParameterTests; -public abstract class - DbConnectionExtensions_ParameterTests : IntegrationTestsBase +public abstract class DbConnectionExtensions_ParameterTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { [Fact] @@ -35,12 +30,12 @@ public void Parameter_EnumValue_EnumSerializationModeIsIntegers_ShouldSerializeE // parameters have different types (integer vs. string). var enumValue1 = Generate.Single(); - this.Connection - .ExecuteScalar( + this.Connection.ExecuteScalar( $"SELECT {Parameter(enumValue1)}", cancellationToken: TestContext.Current.CancellationToken ) - .Should().Be((int)enumValue1); + .Should() + .Be((int)enumValue1); } [Fact] @@ -54,12 +49,12 @@ public void Parameter_EnumValue_EnumSerializationModeIsStrings_ShouldSerializeEn // parameters have different types (integer vs. string). var enumValue2 = Generate.Single(); - this.Connection - .ExecuteScalar( + this.Connection.ExecuteScalar( $"SELECT {Parameter(enumValue2)}", cancellationToken: TestContext.Current.CancellationToken ) - .Should().Be(enumValue2.ToString()); + .Should() + .Be(enumValue2.ToString()); } [Fact] @@ -69,39 +64,39 @@ public void Parameter_MultipleParameters_ShouldPassValuesAsParameters() var guid = Guid.NewGuid(); var dateTime = new DateTime(2025, 12, 31, 23, 59, 59); - this.Connection - .QuerySingle<(long, Guid, DateTime)>( + this.Connection.QuerySingle<(long, Guid, DateTime)>( $"SELECT {Parameter(int64)}, {Parameter(guid)}, {Parameter(dateTime)}", cancellationToken: TestContext.Current.CancellationToken ) - .Should().Be((int64, guid, dateTime)); + .Should() + .Be((int64, guid, dateTime)); } [Fact] public void Parameter_ShouldPassValueAsParameter() { const long int64 = 123L; - this.Connection - .ExecuteScalar( + this.Connection.ExecuteScalar( $"SELECT {Parameter(int64)}", cancellationToken: TestContext.Current.CancellationToken ) - .Should().Be(int64); + .Should() + .Be(int64); var guid = Guid.NewGuid(); - this.Connection - .ExecuteScalar( + this.Connection.ExecuteScalar( $"SELECT {Parameter(guid)}", cancellationToken: TestContext.Current.CancellationToken ) - .Should().Be(guid); + .Should() + .Be(guid); var dateTime = new DateTime(2025, 12, 31, 23, 59, 59); - this.Connection - .ExecuteScalar( + this.Connection.ExecuteScalar( $"SELECT {Parameter(dateTime)}", cancellationToken: TestContext.Current.CancellationToken ) - .Should().Be(dateTime); + .Should() + .Be(dateTime); } } diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOfTTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOfTTests.cs index b005868..d7dcd4d 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOfTTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOfTTests.cs @@ -2,28 +2,23 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests; -public sealed class - DbConnectionExtensions_QueryFirstOfTTests_MySql : - DbConnectionExtensions_QueryFirstOfTTests; +public sealed class DbConnectionExtensions_QueryFirstOfTTests_MySql + : DbConnectionExtensions_QueryFirstOfTTests; -public sealed class - DbConnectionExtensions_QueryFirstOfTTests_Oracle : - DbConnectionExtensions_QueryFirstOfTTests; +public sealed class DbConnectionExtensions_QueryFirstOfTTests_Oracle + : DbConnectionExtensions_QueryFirstOfTTests; -public sealed class - DbConnectionExtensions_QueryFirstOfTTests_PostgreSql : - DbConnectionExtensions_QueryFirstOfTTests; +public sealed class DbConnectionExtensions_QueryFirstOfTTests_PostgreSql + : DbConnectionExtensions_QueryFirstOfTTests; -public sealed class - DbConnectionExtensions_QueryFirstOfTTests_Sqlite : - DbConnectionExtensions_QueryFirstOfTTests; +public sealed class DbConnectionExtensions_QueryFirstOfTTests_Sqlite + : DbConnectionExtensions_QueryFirstOfTTests; -public sealed class - DbConnectionExtensions_QueryFirstOfTTests_SqlServer : - DbConnectionExtensions_QueryFirstOfTTests; +public sealed class DbConnectionExtensions_QueryFirstOfTTests_SqlServer + : DbConnectionExtensions_QueryFirstOfTTests; -public abstract class - DbConnectionExtensions_QueryFirstOfTTests : IntegrationTestsBase +public abstract class DbConnectionExtensions_QueryFirstOfTTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { [Theory] @@ -37,7 +32,8 @@ bool useAsyncApi { // Oracle doesn't allow to return an empty string, because it treats empty strings as NULLs. - (await Invoking(() => + ( + await Invoking(() => CallApi( useAsyncApi, this.Connection, @@ -45,19 +41,22 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value '' ({typeof(string)}), " + - $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" - )) + $"The first column returned by the SQL statement contains the value '' ({typeof(string)}), " + + $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" + ) + ) .WithInnerException() .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly " + - "one character long." + $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly " + + "one character long." ); } - (await Invoking(() => + ( + await Invoking(() => CallApi( useAsyncApi, this.Connection, @@ -65,35 +64,39 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value 'ab' ({typeof(string)}), " + - $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" - )) + $"The first column returned by the SQL statement contains the value 'ab' ({typeof(string)}), " + + $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" + ) + ) .WithInnerException() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + - "one character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + + "one character long." ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirst_BuiltInType_CharTargetType_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - bool useAsyncApi - ) + public async Task QueryFirst_BuiltInType_CharTargetType_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( + bool useAsyncApi + ) { var character = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT '{character}'", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(character); + ) + ) + .Should() + .Be(character); } [Theory] @@ -108,10 +111,11 @@ public Task QueryFirst_BuiltInType_ColumnValueCannotBeConvertedToTargetType_Shou cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value 'A' ({typeof(string)}), which " + - $"could not be converted to the type {typeof(int)}. See inner exception for details.*" + $"The first column returned by the SQL statement contains the value 'A' ({typeof(string)}), which " + + $"could not be converted to the type {typeof(int)}. See inner exception for details.*" ); [Theory] @@ -126,10 +130,11 @@ public Task QueryFirst_BuiltInType_EnumTargetType_ColumnContainsInvalidInteger_S cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column returned by the SQL statement contains the value '999*' (System.*), which " + - $"could not be converted to the type {typeof(TestEnum)}. See inner exception for details.*" + "The first column returned by the SQL statement contains the value '999*' (System.*), which " + + $"could not be converted to the type {typeof(TestEnum)}. See inner exception for details.*" ); [Theory] @@ -144,11 +149,12 @@ public Task QueryFirst_BuiltInType_EnumTargetType_ColumnContainsInvalidString_Sh cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column returned by the SQL statement contains the value 'NonExistent' " + - $"({typeof(string)}), which could not be converted to the type {typeof(TestEnum)}. See inner " + - "exception for details.*" + "The first column returned by the SQL statement contains the value 'NonExistent' " + + $"({typeof(string)}), which could not be converted to the type {typeof(TestEnum)}. See inner " + + "exception for details.*" ); [Theory] @@ -158,13 +164,16 @@ public async Task QueryFirst_BuiltInType_EnumTargetType_ShouldConvertIntegerToEn { var enumValue = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT {(int)enumValue}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(enumValue); + ) + ) + .Should() + .Be(enumValue); } [Theory] @@ -174,13 +183,16 @@ public async Task QueryFirst_BuiltInType_EnumTargetType_ShouldConvertStringToEnu { var enumValue = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT '{enumValue.ToString()}'", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(enumValue); + ) + ) + .Should() + .Be(enumValue); } [Theory] @@ -195,25 +207,27 @@ public Task QueryFirst_BuiltInType_NonNullableTargetType_ColumnContainsNull_Shou cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column returned by the SQL statement contains a NULL value, which could not be converted " + - $"to the type {typeof(int)}. See inner exception for details.*" + "The first column returned by the SQL statement contains a NULL value, which could not be converted " + + $"to the type {typeof(int)}. See inner exception for details.*" ); [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_BuiltInType_NullableTargetType_ColumnContainsNull_ShouldReturnNull( - bool useAsyncApi - ) => - (await CallApi( - useAsyncApi, - this.Connection, - "SELECT NULL", - cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeNull(); + public async Task QueryFirst_BuiltInType_NullableTargetType_ColumnContainsNull_ShouldReturnNull(bool useAsyncApi) => + ( + await CallApi( + useAsyncApi, + this.Connection, + "SELECT NULL", + cancellationToken: TestContext.Current.CancellationToken + ) + ) + .Should() + .BeNull(); [Theory] [InlineData(false)] @@ -224,13 +238,16 @@ public async Task QueryFirst_BuiltInType_ShouldSupportDateTimeOffsetValues(bool var entities = this.CreateEntitiesInDb(2); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("DateTimeOffsetValue")} FROM {Q("EntityWithDateTimeOffset")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(entities[0].DateTimeOffsetValue); + ) + ) + .Should() + .Be(entities[0].DateTimeOffsetValue); } [Theory] @@ -252,7 +269,8 @@ await Invoking(() => cancellationToken: cancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); } @@ -265,21 +283,23 @@ public async Task QueryFirst_CommandType_ShouldUseCommandType(bool useAsyncApi) var entities = this.CreateEntitiesInDb(2); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, "GetEntities", commandType: CommandType.StoredProcedure, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirst_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) + public async Task QueryFirst_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -289,44 +309,49 @@ public async Task var temporaryTableName = statement.TemporaryTables[0].Name; - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, statement, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirst_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - bool useAsyncApi - ) + public async Task QueryFirst_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entities = Generate.Multiple(2); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {TemporaryTable(entities)}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirst_EntityType_CharEntityProperty_ColumnContainsStringWithLengthNotOne_ShouldThrow(bool useAsyncApi) + public async Task QueryFirst_EntityType_CharEntityProperty_ColumnContainsStringWithLengthNotOne_ShouldThrow( + bool useAsyncApi + ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) { @@ -340,16 +365,17 @@ await Invoking(() => cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'CharValue' returned by the SQL statement contains a value that could not be " + - $"converted to the type {typeof(char)} of the corresponding property of the type " + - $"{typeof(Entity)}. See inner exception for details.*" + "The column 'CharValue' returned by the SQL statement contains a value that could not be " + + $"converted to the type {typeof(char)} of the corresponding property of the type " + + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } @@ -361,44 +387,45 @@ await Invoking(() => cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(char)} of the corresponding property of the type " + - $"{typeof(Entity)}. See inner exception for details.*" + "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + + $"to the type {typeof(char)} of the corresponding property of the type " + + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirst_EntityType_CharEntityProperty_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - bool useAsyncApi - ) + public async Task QueryFirst_EntityType_CharEntityProperty_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( + bool useAsyncApi + ) { var character = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT '{character}' AS {Q("CharValue")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(new Entity { CharValue = character }); + ) + ) + .Should() + .BeEquivalentTo(new Entity { CharValue = character }); } [Theory] [InlineData(false)] [InlineData(true)] - public Task QueryFirst_EntityType_ColumnDataTypeNotCompatibleWithEntityPropertyType_ShouldThrow( - bool useAsyncApi - ) => + public Task QueryFirst_EntityType_ColumnDataTypeNotCompatibleWithEntityPropertyType_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi( useAsyncApi, @@ -407,11 +434,12 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The data type System.* of the column 'TimeSpanValue' returned by the SQL statement is not " + - $"compatible with the property type {typeof(TimeSpan)} of the corresponding property of the type " + - $"{typeof(Entity)}.*" + "The data type System.* of the column 'TimeSpanValue' returned by the SQL statement is not " + + $"compatible with the property type {typeof(TimeSpan)} of the corresponding property of the type " + + $"{typeof(Entity)}.*" ); [Theory] @@ -421,14 +449,11 @@ public async Task QueryFirst_EntityType_ColumnHasNoName_ShouldThrow(bool useAsyn { InterpolatedSqlStatement statement = this.TestDatabaseProvider switch { - SqlServerTestDatabaseProvider => - "SELECT 1", + SqlServerTestDatabaseProvider => "SELECT 1", - PostgreSqlTestDatabaseProvider or OracleTestDatabaseProvider => - "SELECT 1 AS \" \"", + PostgreSqlTestDatabaseProvider or OracleTestDatabaseProvider => "SELECT 1 AS \" \"", - _ => - "SELECT 1 AS ''" + _ => "SELECT 1 AS ''", }; await Invoking(() => @@ -439,29 +464,31 @@ await Invoking(() => cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The 1st column returned by the SQL statement does not have a name. Make sure that all columns the " + - "statement returns have a name.*" + "The 1st column returned by the SQL statement does not have a name. Make sure that all columns the " + + "statement returns have a name.*" ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_EntityType_CompatiblePrivateConstructor_ShouldUsePrivateConstructor( - bool useAsyncApi - ) + public async Task QueryFirst_EntityType_CompatiblePrivateConstructor_ShouldUsePrivateConstructor(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(2); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); } [Theory] @@ -471,13 +498,16 @@ public async Task QueryFirst_EntityType_CompatiblePublicConstructor_ShouldUsePub { var entities = this.CreateEntitiesInDb(2); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); } [Theory] @@ -487,18 +517,20 @@ public async Task QueryFirst_EntityType_EntityTypeHasNoCorrespondingPropertyForC bool useAsyncApi ) { - var entity = (await Invoking(() => - CallApi( - useAsyncApi, - this.Connection, - $"SELECT 1 AS {Q("Id")}, 2 AS {Q("Int32Value")}, 3 AS {Q("NonExistent")}", - cancellationToken: TestContext.Current.CancellationToken + var entity = ( + await Invoking(() => + CallApi( + useAsyncApi, + this.Connection, + $"SELECT 1 AS {Q("Id")}, 2 AS {Q("Int32Value")}, 3 AS {Q("NonExistent")}", + cancellationToken: TestContext.Current.CancellationToken + ) ) - ) - .Should().NotThrowAsync()).Subject; + .Should() + .NotThrowAsync() + ).Subject; - entity - .Should().BeEquivalentTo(new Entity { Id = 1, Int32Value = 2 }); + entity.Should().BeEquivalentTo(new Entity { Id = 1, Int32Value = 2 }); } [Theory] @@ -511,13 +543,16 @@ bool useAsyncApi var entities = this.CreateEntitiesInDb(2); var entitiesWithDifferentCasingProperties = Generate.MapTo(entities); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entitiesWithDifferentCasingProperties[0]); + ) + ) + .Should() + .BeEquivalentTo(entitiesWithDifferentCasingProperties[0]); } [Theory] @@ -526,23 +561,25 @@ bool useAsyncApi public async Task QueryFirst_EntityType_EnumEntityProperty_ColumnContainsInvalidInteger_ShouldThrow( bool useAsyncApi ) => - await Invoking(() => CallApi( + await Invoking(() => + CallApi( useAsyncApi, this.Connection, $"SELECT 1 AS {Q("Id")}, 999 AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding property of the type " + - $"{typeof(EntityWithEnumStoredAsInteger)}. See inner exception for details.*" + "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding property of the type " + + $"{typeof(EntityWithEnumStoredAsInteger)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - "Could not convert the value '999*' (System.*) to an enum member of the type " + - $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" + "Could not convert the value '999*' (System.*) to an enum member of the type " + + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); [Theory] @@ -551,23 +588,25 @@ await Invoking(() => CallApi( public async Task QueryFirst_EntityType_EnumEntityProperty_ColumnContainsInvalidString_ShouldThrow( bool useAsyncApi ) => - await Invoking(() => CallApi( + await Invoking(() => + CallApi( useAsyncApi, this.Connection, $"SELECT 1 AS {Q("Id")}, 'NonExistent' AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding property of the type " + - $"{typeof(EntityWithEnumStoredAsString)}. See inner exception for details.*" + "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding property of the type " + + $"{typeof(EntityWithEnumStoredAsString)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + - "That string does not match any of the names of the enum's members.*" + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + + "That string does not match any of the names of the enum's members.*" ); [Theory] @@ -577,14 +616,16 @@ public async Task QueryFirst_EntityType_EnumEntityProperty_ShouldConvertIntegerT { var enumValue = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT 1 AS {Q("Id")}, {(int)enumValue} AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Enum - .Should().Be(enumValue); + ) + ) + .Enum.Should() + .Be(enumValue); } [Theory] @@ -594,14 +635,16 @@ public async Task QueryFirst_EntityType_EnumEntityProperty_ShouldConvertStringTo { var enumValue = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT 1 AS {Q("Id")}, '{enumValue.ToString()}' AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Enum - .Should().Be(enumValue); + ) + ) + .Enum.Should() + .Be(enumValue); } [Theory] @@ -611,16 +654,21 @@ public async Task QueryFirst_EntityType_Mapping_Attributes_ShouldUseAttributesMa { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("MappingTestEntity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo( + ) + ) + .Should() + .BeEquivalentTo( entity, - options => options.Using(context => context.Subject.Should().BeNull()) - .When(info => info.Path.EndsWith("NotMapped")) + options => + options + .Using(context => context.Subject.Should().BeNull()) + .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -633,16 +681,21 @@ public async Task QueryFirst_EntityType_Mapping_FluentApi_ShouldUseFluentApiMapp var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("MappingTestEntity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo( + ) + ) + .Should() + .BeEquivalentTo( entity, - options => options.Using(context => context.Subject.Should().BeNull()) - .When(info => info.Path.EndsWith("NotMapped")) + options => + options + .Using(context => context.Subject.Should().BeNull()) + .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -655,51 +708,56 @@ bool useAsyncApi Invoking(() => CallApi(useAsyncApi, this.Connection, $"SELECT 1 AS {Q("NonExistent")}") ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"Could not materialize an instance of the type {typeof(EntityWithPublicConstructor)}. The type " + - "either needs to have a parameterless constructor or a constructor whose parameters match the " + - "columns returned by the SQL statement, e.g. a constructor that has the following " + - $"signature:{Environment.NewLine}" + - "(* NonExistent).*" + $"Could not materialize an instance of the type {typeof(EntityWithPublicConstructor)}. The type " + + "either needs to have a parameterless constructor or a constructor whose parameters match the " + + "columns returned by the SQL statement, e.g. a constructor that has the following " + + $"signature:{Environment.NewLine}" + + "(* NonExistent).*" ); [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirst_EntityType_NoCompatibleConstructor_PrivateParameterlessConstructor_ShouldUsePrivateConstructorAndProperties( - bool useAsyncApi - ) + public async Task QueryFirst_EntityType_NoCompatibleConstructor_PrivateParameterlessConstructor_ShouldUsePrivateConstructorAndProperties( + bool useAsyncApi + ) { var entities = this.CreateEntitiesInDb(2); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirst_EntityType_NoCompatibleConstructor_PublicParameterlessConstructor_ShouldUsePublicConstructorAndProperties( - bool useAsyncApi - ) + public async Task QueryFirst_EntityType_NoCompatibleConstructor_PublicParameterlessConstructor_ShouldUsePublicConstructorAndProperties( + bool useAsyncApi + ) { var entities = this.CreateEntitiesInDb(2); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); } [Theory] @@ -709,13 +767,16 @@ public async Task QueryFirst_EntityType_NoMapping_ShouldUseEntityTypeNameAndProp { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("MappingTestEntity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] @@ -723,9 +784,7 @@ public async Task QueryFirst_EntityType_NoMapping_ShouldUseEntityTypeNameAndProp [InlineData(true)] public Task QueryFirst_EntityType_NonNullableEntityProperty_ColumnContainsNull_ShouldThrow(bool useAsyncApi) { - this.Connection.ExecuteNonQuery( - $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)" - ); + this.Connection.ExecuteNonQuery($"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)"); return Invoking(() => CallApi( @@ -735,31 +794,33 @@ public Task QueryFirst_EntityType_NonNullableEntityProperty_ColumnContainsNull_S cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + - $"corresponding property of the type {typeof(Entity)} is non-nullable.*" + "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + + $"corresponding property of the type {typeof(Entity)} is non-nullable.*" ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_EntityType_NullableEntityProperty_ColumnContainsNull_ShouldReturnNull( - bool useAsyncApi - ) + public async Task QueryFirst_EntityType_NullableEntityProperty_ColumnContainsNull_ShouldReturnNull(bool useAsyncApi) { await this.Connection.ExecuteNonQueryAsync( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("NullableBooleanValue")}) VALUES(1, NULL)" ); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("Id")}, {Q("NullableBooleanValue")} FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(new Entity { Id = 1, NullableBooleanValue = null }); + ) + ) + .Should() + .BeEquivalentTo(new Entity { Id = 1, NullableBooleanValue = null }); } [Theory] @@ -771,13 +832,16 @@ public async Task QueryFirst_EntityType_ShouldSupportDateTimeOffsetValues(bool u var entities = this.CreateEntitiesInDb(2); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("EntityWithDateTimeOffset")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); } [Theory] @@ -797,7 +861,8 @@ public Task QueryFirst_EntityType_UnsupportedFieldType_ShouldThrow(bool useAsync cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( "The data type System.* of the column 'Value' returned by the SQL statement is not supported.*" ); @@ -810,13 +875,16 @@ public async Task QueryFirst_InterpolatedParameter_ShouldPassInterpolatedParamet { var entities = this.CreateEntitiesInDb(2); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")} WHERE {Q("Id")} = {Parameter(entities[0].Id)}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); } [Theory] @@ -831,82 +899,85 @@ public async Task QueryFirst_Parameter_ShouldPassParameter(bool useAsyncApi) ("Id", entities[0].Id) ); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, statement, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); } [Theory] [InlineData(false)] [InlineData(true)] public Task QueryFirst_QueryReturnedNoRows_ShouldThrow(bool useAsyncApi) => - Invoking(() => CallApi( + Invoking(() => + CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")} WHERE {Q("Id")} = -1", cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() - .WithMessage( - "The SQL statement did not return any rows." - ); + .Should() + .ThrowAsync() + .WithMessage("The SQL statement did not return any rows."); [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirst_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) + public async Task QueryFirst_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entityIds = Generate.Ids(2); - InterpolatedSqlStatement statement = - $"SELECT {Q("Value")} AS {Q("Id")} FROM {TemporaryTable(entityIds)}"; + InterpolatedSqlStatement statement = $"SELECT {Q("Value")} AS {Q("Id")} FROM {TemporaryTable(entityIds)}"; var temporaryTableName = statement.TemporaryTables[0].Name; - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, statement, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(entityIds[0]); + ) + ) + .Should() + .Be(entityIds[0]); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirst_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - bool useAsyncApi - ) + public async Task QueryFirst_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entities = this.CreateEntitiesInDb(2); var entityIds = entities.ConvertAll(a => a.Id); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $""" - SELECT * - FROM {Q("Entity")} - WHERE {Q("Id")} IN (SELECT {Q("Value")} FROM {TemporaryTable(entityIds)}) - """, + SELECT * + FROM {Q("Entity")} + WHERE {Q("Id")} IN (SELECT {Q("Value")} FROM {TemporaryTable(entityIds)}) + """, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ).Should().BeEquivalentTo(entities[0]); } [Theory] @@ -918,35 +989,39 @@ public async Task QueryFirst_Transaction_ShouldUseTransaction(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(2, transaction); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", transaction, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); await transaction.RollbackAsync(); } - await Invoking(() => CallApi( + await Invoking(() => + CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync(); + .Should() + .ThrowAsync(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirst_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthNotOne_ShouldThrow( - bool useAsyncApi - ) + public async Task QueryFirst_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthNotOne_ShouldThrow( + bool useAsyncApi + ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) { @@ -960,16 +1035,17 @@ await Invoking(() => cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Value' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Value' returned by the SQL statement contains a value that could not be converted " + + $"to the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } @@ -981,36 +1057,39 @@ await Invoking(() => cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Value' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Value' returned by the SQL statement contains a value that could not be converted " + + $"to the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirst_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - bool useAsyncApi - ) + public async Task QueryFirst_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( + bool useAsyncApi + ) { var character = Generate.Single(); - (await CallApi>( + ( + await CallApi>( useAsyncApi, this.Connection, $"SELECT '{character}'", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(ValueTuple.Create(character)); + ) + ) + .Should() + .Be(ValueTuple.Create(character)); } [Theory] @@ -1027,11 +1106,12 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The data type System.* of the column 'Value' returned by the SQL statement is not compatible with " + - $"the field type {typeof(TimeSpan)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}.*" + "The data type System.* of the column 'Value' returned by the SQL statement is not compatible with " + + $"the field type {typeof(TimeSpan)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}.*" ); [Theory] @@ -1048,16 +1128,17 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Value' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Value' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - "Could not convert the value '999*' (System.*) to an enum member of the type " + - $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" + "Could not convert the value '999*' (System.*) to an enum member of the type " + + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); [Theory] @@ -1074,16 +1155,17 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Value' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Value' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + - "That string does not match any of the names of the enum's members.*" + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + + "That string does not match any of the names of the enum's members.*" ); [Theory] @@ -1093,13 +1175,16 @@ public async Task QueryFirst_ValueTupleType_EnumValueTupleField_ShouldConvertInt { var enumValue = Generate.Single(); - (await CallApi>( + ( + await CallApi>( useAsyncApi, this.Connection, $"SELECT {(int)enumValue}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(ValueTuple.Create(enumValue)); + ) + ) + .Should() + .Be(ValueTuple.Create(enumValue)); } [Theory] @@ -1109,13 +1194,16 @@ public async Task QueryFirst_ValueTupleType_EnumValueTupleField_ShouldConvertStr { var enumValue = Generate.Single(); - (await CallApi>( + ( + await CallApi>( useAsyncApi, this.Connection, $"SELECT '{enumValue}'", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(ValueTuple.Create(enumValue)); + ) + ) + .Should() + .Be(ValueTuple.Create(enumValue)); } [Theory] @@ -1123,9 +1211,7 @@ public async Task QueryFirst_ValueTupleType_EnumValueTupleField_ShouldConvertStr [InlineData(true)] public Task QueryFirst_ValueTupleType_NonNullableValueTupleField_ColumnContainsNull_ShouldThrow(bool useAsyncApi) { - this.Connection.ExecuteNonQuery( - $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)" - ); + this.Connection.ExecuteNonQuery($"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)"); return Invoking(() => CallApi>( @@ -1135,10 +1221,11 @@ public Task QueryFirst_ValueTupleType_NonNullableValueTupleField_ColumnContainsN cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + - $"corresponding field of the value tuple type {typeof(ValueTuple)} is non-nullable.*" + "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + + $"corresponding field of the value tuple type {typeof(ValueTuple)} is non-nullable.*" ); } @@ -1153,13 +1240,16 @@ await this.Connection.ExecuteNonQueryAsync( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("NullableBooleanValue")}) VALUES(1, NULL)" ); - (await CallApi>( + ( + await CallApi>( useAsyncApi, this.Connection, $"SELECT {Q("NullableBooleanValue")} FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(new(null)); + ) + ) + .Should() + .Be(new(null)); } [Theory] @@ -1176,11 +1266,12 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The SQL statement returned 1 column, but the value tuple type {typeof((int, int))} has 2 " + - "fields. Make sure that the SQL statement returns the same number of columns as the number of " + - "fields in the value tuple type.*" + $"The SQL statement returned 1 column, but the value tuple type {typeof((int, int))} has 2 " + + "fields. Make sure that the SQL statement returns the same number of columns as the number of " + + "fields in the value tuple type.*" ); [Theory] @@ -1190,13 +1281,16 @@ public async Task QueryFirst_ValueTupleType_ShouldMaterializeBinaryData(bool use { var bytes = Generate.Single(); - (await CallApi>( + ( + await CallApi>( useAsyncApi, this.Connection, $"SELECT {Parameter(bytes)} AS BinaryData", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(ValueTuple.Create(bytes)); + ) + ) + .Should() + .BeEquivalentTo(ValueTuple.Create(bytes)); } [Theory] @@ -1208,13 +1302,16 @@ public async Task QueryFirst_ValueTupleType_ShouldSupportDateTimeOffsetValues(bo var entities = this.CreateEntitiesInDb(2); - (await CallApi<(long Id, DateTimeOffset DateTimeOffsetValue)>( + ( + await CallApi<(long Id, DateTimeOffset DateTimeOffsetValue)>( useAsyncApi, this.Connection, $"SELECT {Q("Id")}, {Q("DateTimeOffsetValue")} FROM {Q("EntityWithDateTimeOffset")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be((entities[0].Id, entities[0].DateTimeOffsetValue)); + ) + ) + .Should() + .Be((entities[0].Id, entities[0].DateTimeOffsetValue)); } [Theory] @@ -1234,7 +1331,8 @@ public Task QueryFirst_ValueTupleType_UnsupportedFieldType_ShouldThrow(bool useA cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( "The data type System.* of the column 'Value' returned by the SQL statement is not supported.*" ); @@ -1264,13 +1362,7 @@ private static Task CallApi( try { return Task.FromResult( - connection.QueryFirst( - statement, - transaction, - commandTimeout, - commandType, - cancellationToken - ) + connection.QueryFirst(statement, transaction, commandTimeout, commandType, cancellationToken) ); } catch (Exception ex) diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOrDefaultOfTTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOrDefaultOfTTests.cs index 8933e91..2029f45 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOrDefaultOfTTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOrDefaultOfTTests.cs @@ -2,44 +2,38 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests; -public sealed class - DbConnectionExtensions_QueryFirstOrDefaultOfTTests_MySql : - DbConnectionExtensions_QueryFirstOrDefaultOfTTests; +public sealed class DbConnectionExtensions_QueryFirstOrDefaultOfTTests_MySql + : DbConnectionExtensions_QueryFirstOrDefaultOfTTests; -public sealed class - DbConnectionExtensions_QueryFirstOrDefaultOfTTests_Oracle : - DbConnectionExtensions_QueryFirstOrDefaultOfTTests; +public sealed class DbConnectionExtensions_QueryFirstOrDefaultOfTTests_Oracle + : DbConnectionExtensions_QueryFirstOrDefaultOfTTests; -public sealed class - DbConnectionExtensions_QueryFirstOrDefaultOfTTests_PostgreSql : - DbConnectionExtensions_QueryFirstOrDefaultOfTTests; +public sealed class DbConnectionExtensions_QueryFirstOrDefaultOfTTests_PostgreSql + : DbConnectionExtensions_QueryFirstOrDefaultOfTTests; -public sealed class - DbConnectionExtensions_QueryFirstOrDefaultOfTTests_Sqlite : - DbConnectionExtensions_QueryFirstOrDefaultOfTTests; +public sealed class DbConnectionExtensions_QueryFirstOrDefaultOfTTests_Sqlite + : DbConnectionExtensions_QueryFirstOrDefaultOfTTests; -public sealed class - DbConnectionExtensions_QueryFirstOrDefaultOfTTests_SqlServer : - DbConnectionExtensions_QueryFirstOrDefaultOfTTests; +public sealed class DbConnectionExtensions_QueryFirstOrDefaultOfTTests_SqlServer + : DbConnectionExtensions_QueryFirstOrDefaultOfTTests; -public abstract class - DbConnectionExtensions_QueryFirstOrDefaultOfTTests : IntegrationTestsBase< - TTestDatabaseProvider> +public abstract class DbConnectionExtensions_QueryFirstOrDefaultOfTTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirstOrDefault_BuiltInType_CharTargetType_ColumnContainsStringWithLengthNotOne_ShouldThrow( - bool useAsyncApi - ) + public async Task QueryFirstOrDefault_BuiltInType_CharTargetType_ColumnContainsStringWithLengthNotOne_ShouldThrow( + bool useAsyncApi + ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) { // Oracle doesn't allow to return an empty string, because it treats empty strings as NULLs. - (await Invoking(() => + ( + await Invoking(() => CallApi( useAsyncApi, this.Connection, @@ -47,19 +41,22 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value '' ({typeof(string)}), " + - $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" - )) + $"The first column returned by the SQL statement contains the value '' ({typeof(string)}), " + + $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" + ) + ) .WithInnerException() .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly " + - "one character long." + $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly " + + "one character long." ); } - (await Invoking(() => + ( + await Invoking(() => CallApi( useAsyncApi, this.Connection, @@ -67,35 +64,39 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value 'ab' ({typeof(string)}), " + - $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" - )) + $"The first column returned by the SQL statement contains the value 'ab' ({typeof(string)}), " + + $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" + ) + ) .WithInnerException() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + - "one character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + + "one character long." ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirstOrDefault_BuiltInType_CharTargetType_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - bool useAsyncApi - ) + public async Task QueryFirstOrDefault_BuiltInType_CharTargetType_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( + bool useAsyncApi + ) { var character = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT '{character}'", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(character); + ) + ) + .Should() + .Be(character); } [Theory] @@ -112,10 +113,11 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value 'A' ({typeof(string)}), which " + - $"could not be converted to the type {typeof(int)}. See inner exception for details.*" + $"The first column returned by the SQL statement contains the value 'A' ({typeof(string)}), which " + + $"could not be converted to the type {typeof(int)}. See inner exception for details.*" ); [Theory] @@ -132,10 +134,11 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column returned by the SQL statement contains the value '999*' (System.*), which " + - $"could not be converted to the type {typeof(TestEnum)}. See inner exception for details.*" + "The first column returned by the SQL statement contains the value '999*' (System.*), which " + + $"could not be converted to the type {typeof(TestEnum)}. See inner exception for details.*" ); [Theory] @@ -152,11 +155,12 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column returned by the SQL statement contains the value 'NonExistent' " + - $"({typeof(string)}), which could not be converted to the type {typeof(TestEnum)}. See inner " + - "exception for details.*" + "The first column returned by the SQL statement contains the value 'NonExistent' " + + $"({typeof(string)}), which could not be converted to the type {typeof(TestEnum)}. See inner " + + "exception for details.*" ); [Theory] @@ -166,13 +170,16 @@ public async Task QueryFirstOrDefault_BuiltInType_EnumTargetType_ShouldConvertIn { var enumValue = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT {(int)enumValue}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(enumValue); + ) + ) + .Should() + .Be(enumValue); } [Theory] @@ -182,13 +189,16 @@ public async Task QueryFirstOrDefault_BuiltInType_EnumTargetType_ShouldConvertSt { var enumValue = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT '{enumValue.ToString()}'", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(enumValue); + ) + ) + .Should() + .Be(enumValue); } [Theory] @@ -205,10 +215,11 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column returned by the SQL statement contains a NULL value, which could not be converted " + - $"to the type {typeof(int)}. See inner exception for details.*" + "The first column returned by the SQL statement contains a NULL value, which could not be converted " + + $"to the type {typeof(int)}. See inner exception for details.*" ); [Theory] @@ -217,13 +228,16 @@ bool useAsyncApi public async Task QueryFirstOrDefault_BuiltInType_NullableTargetType_ColumnContainsNull_ShouldReturnNull( bool useAsyncApi ) => - (await CallApi( - useAsyncApi, - this.Connection, - "SELECT NULL", - cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeNull(); + ( + await CallApi( + useAsyncApi, + this.Connection, + "SELECT NULL", + cancellationToken: TestContext.Current.CancellationToken + ) + ) + .Should() + .BeNull(); [Theory] [InlineData(false)] @@ -234,13 +248,16 @@ public async Task QueryFirstOrDefault_BuiltInType_ShouldSupportDateTimeOffsetVal var entities = this.CreateEntitiesInDb(2); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("DateTimeOffsetValue")} FROM {Q("EntityWithDateTimeOffset")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(entities[0].DateTimeOffsetValue); + ) + ) + .Should() + .Be(entities[0].DateTimeOffsetValue); } [Theory] @@ -264,7 +281,8 @@ await Invoking(() => cancellationToken: cancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); } @@ -277,21 +295,25 @@ public async Task QueryFirstOrDefault_CommandType_ShouldUseCommandType(bool useA var entities = this.CreateEntitiesInDb(2); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, "GetEntities", commandType: CommandType.StoredProcedure, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirstOrDefault_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) + public async Task QueryFirstOrDefault_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -301,46 +323,49 @@ public async Task var temporaryTableName = statement.TemporaryTables[0].Name; - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, statement, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirstOrDefault_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - bool useAsyncApi - ) + public async Task QueryFirstOrDefault_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entities = Generate.Multiple(2); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {TemporaryTable(entities)}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirstOrDefault_EntityType_CharEntityProperty_ColumnContainsStringWithLengthNotOne_ShouldThrow( - bool useAsyncApi - ) + public async Task QueryFirstOrDefault_EntityType_CharEntityProperty_ColumnContainsStringWithLengthNotOne_ShouldThrow( + bool useAsyncApi + ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) { @@ -354,16 +379,17 @@ await Invoking(() => cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'CharValue' returned by the SQL statement contains a value that could not be " + - $"converted to the type {typeof(char)} of the corresponding property of the type " + - $"{typeof(Entity)}. See inner exception for details.*" + "The column 'CharValue' returned by the SQL statement contains a value that could not be " + + $"converted to the type {typeof(char)} of the corresponding property of the type " + + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } @@ -375,36 +401,39 @@ await Invoking(() => cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(char)} of the corresponding property of the type " + - $"{typeof(Entity)}. See inner exception for details.*" + "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + + $"to the type {typeof(char)} of the corresponding property of the type " + + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirstOrDefault_EntityType_CharEntityProperty_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - bool useAsyncApi - ) + public async Task QueryFirstOrDefault_EntityType_CharEntityProperty_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( + bool useAsyncApi + ) { var character = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT '{character}' AS {Q("CharValue")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(new Entity { CharValue = character }); + ) + ) + .Should() + .BeEquivalentTo(new Entity { CharValue = character }); } [Theory] @@ -421,11 +450,12 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The data type System.* of the column 'TimeSpanValue' returned by the SQL statement is not " + - $"compatible with the property type {typeof(TimeSpan)} of the corresponding property of the type " + - $"{typeof(Entity)}.*" + "The data type System.* of the column 'TimeSpanValue' returned by the SQL statement is not " + + $"compatible with the property type {typeof(TimeSpan)} of the corresponding property of the type " + + $"{typeof(Entity)}.*" ); [Theory] @@ -435,14 +465,11 @@ public async Task QueryFirstOrDefault_EntityType_ColumnHasNoName_ShouldThrow(boo { InterpolatedSqlStatement statement = this.TestDatabaseProvider switch { - SqlServerTestDatabaseProvider => - "SELECT 1", + SqlServerTestDatabaseProvider => "SELECT 1", - PostgreSqlTestDatabaseProvider or OracleTestDatabaseProvider => - "SELECT 1 AS \" \"", + PostgreSqlTestDatabaseProvider or OracleTestDatabaseProvider => "SELECT 1 AS \" \"", - _ => - "SELECT 1 AS ''" + _ => "SELECT 1 AS ''", }; await Invoking(() => @@ -453,10 +480,11 @@ await Invoking(() => cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The 1st column returned by the SQL statement does not have a name. Make sure that all columns the " + - "statement returns have a name.*" + "The 1st column returned by the SQL statement does not have a name. Make sure that all columns the " + + "statement returns have a name.*" ); } @@ -469,13 +497,16 @@ bool useAsyncApi { var entities = this.CreateEntitiesInDb(2); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); } [Theory] @@ -487,107 +518,115 @@ bool useAsyncApi { var entities = this.CreateEntitiesInDb(2); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirstOrDefault_EntityType_EntityTypeHasNoCorrespondingPropertyForColumn_ShouldIgnoreColumn( - bool useAsyncApi - ) + public async Task QueryFirstOrDefault_EntityType_EntityTypeHasNoCorrespondingPropertyForColumn_ShouldIgnoreColumn( + bool useAsyncApi + ) { - var entity = (await Invoking(() => - CallApi( - useAsyncApi, - this.Connection, - $"SELECT 1 AS {Q("Id")}, 2 AS {Q("Int32Value")}, 3 AS {Q("NonExistent")}", - cancellationToken: TestContext.Current.CancellationToken + var entity = ( + await Invoking(() => + CallApi( + useAsyncApi, + this.Connection, + $"SELECT 1 AS {Q("Id")}, 2 AS {Q("Int32Value")}, 3 AS {Q("NonExistent")}", + cancellationToken: TestContext.Current.CancellationToken + ) ) - ) - .Should().NotThrowAsync()).Subject; + .Should() + .NotThrowAsync() + ).Subject; - entity - .Should().BeEquivalentTo(new Entity { Id = 1, Int32Value = 2 }); + entity.Should().BeEquivalentTo(new Entity { Id = 1, Int32Value = 2 }); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirstOrDefault_EntityType_EntityTypeWithPropertiesWithDifferentCasing_ShouldMaterializeEntities( - bool useAsyncApi - ) + public async Task QueryFirstOrDefault_EntityType_EntityTypeWithPropertiesWithDifferentCasing_ShouldMaterializeEntities( + bool useAsyncApi + ) { var entities = this.CreateEntitiesInDb(2); var entitiesWithDifferentCasingProperties = Generate.MapTo(entities); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entitiesWithDifferentCasingProperties[0]); + ) + ) + .Should() + .BeEquivalentTo(entitiesWithDifferentCasingProperties[0]); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirstOrDefault_EntityType_EnumEntityProperty_ColumnContainsInvalidInteger_ShouldThrow( - bool useAsyncApi - ) => - await Invoking(() => CallApi( + public async Task QueryFirstOrDefault_EntityType_EnumEntityProperty_ColumnContainsInvalidInteger_ShouldThrow( + bool useAsyncApi + ) => + await Invoking(() => + CallApi( useAsyncApi, this.Connection, $"SELECT 1 AS {Q("Id")}, 999 AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding property of the type " + - $"{typeof(EntityWithEnumStoredAsInteger)}. See inner exception for details.*" + "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding property of the type " + + $"{typeof(EntityWithEnumStoredAsInteger)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - "Could not convert the value '999*' (System.*) to an enum member of the type " + - $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" + "Could not convert the value '999*' (System.*) to an enum member of the type " + + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirstOrDefault_EntityType_EnumEntityProperty_ColumnContainsInvalidString_ShouldThrow( - bool useAsyncApi - ) => - await Invoking(() => CallApi( + public async Task QueryFirstOrDefault_EntityType_EnumEntityProperty_ColumnContainsInvalidString_ShouldThrow( + bool useAsyncApi + ) => + await Invoking(() => + CallApi( useAsyncApi, this.Connection, $"SELECT 1 AS {Q("Id")}, 'NonExistent' AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding property of the type " + - $"{typeof(EntityWithEnumStoredAsString)}. See inner exception for details.*" + "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding property of the type " + + $"{typeof(EntityWithEnumStoredAsString)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + - "That string does not match any of the names of the enum's members.*" + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + + "That string does not match any of the names of the enum's members.*" ); [Theory] @@ -597,14 +636,16 @@ public async Task QueryFirstOrDefault_EntityType_EnumEntityProperty_ShouldConver { var enumValue = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT 1 AS {Q("Id")}, {(int)enumValue} AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken - ))! - .Enum - .Should().Be(enumValue); + ) + )! + .Enum.Should() + .Be(enumValue); } [Theory] @@ -614,14 +655,16 @@ public async Task QueryFirstOrDefault_EntityType_EnumEntityProperty_ShouldConver { var enumValue = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT 1 AS {Q("Id")}, '{enumValue.ToString()}' AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken - ))! - .Enum - .Should().Be(enumValue); + ) + )! + .Enum.Should() + .Be(enumValue); } [Theory] @@ -631,16 +674,21 @@ public async Task QueryFirstOrDefault_EntityType_Mapping_Attributes_ShouldUseAtt { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("MappingTestEntity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo( + ) + ) + .Should() + .BeEquivalentTo( entity, - options => options.Using(context => context.Subject.Should().BeNull()) - .When(info => info.Path.EndsWith("NotMapped")) + options => + options + .Using(context => context.Subject.Should().BeNull()) + .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -653,16 +701,21 @@ public async Task QueryFirstOrDefault_EntityType_Mapping_FluentApi_ShouldUseFlue var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("MappingTestEntity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo( + ) + ) + .Should() + .BeEquivalentTo( entity, - options => options.Using(context => context.Subject.Should().BeNull()) - .When(info => info.Path.EndsWith("NotMapped")) + options => + options + .Using(context => context.Subject.Should().BeNull()) + .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -675,69 +728,75 @@ bool useAsyncApi Invoking(() => CallApi(useAsyncApi, this.Connection, $"SELECT 1 AS {Q("NonExistent")}") ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"Could not materialize an instance of the type {typeof(EntityWithPublicConstructor)}. The type " + - "either needs to have a parameterless constructor or a constructor whose parameters match the " + - "columns returned by the SQL statement, e.g. a constructor that has the following " + - $"signature:{Environment.NewLine}" + - "(* NonExistent).*" + $"Could not materialize an instance of the type {typeof(EntityWithPublicConstructor)}. The type " + + "either needs to have a parameterless constructor or a constructor whose parameters match the " + + "columns returned by the SQL statement, e.g. a constructor that has the following " + + $"signature:{Environment.NewLine}" + + "(* NonExistent).*" ); [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirstOrDefault_EntityType_NoCompatibleConstructor_PrivateParameterlessConstructor_ShouldUsePrivateConstructorAndProperties( - bool useAsyncApi - ) + public async Task QueryFirstOrDefault_EntityType_NoCompatibleConstructor_PrivateParameterlessConstructor_ShouldUsePrivateConstructorAndProperties( + bool useAsyncApi + ) { var entities = this.CreateEntitiesInDb(2); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirstOrDefault_EntityType_NoCompatibleConstructor_PublicParameterlessConstructor_ShouldUsePublicConstructorAndProperties( - bool useAsyncApi - ) + public async Task QueryFirstOrDefault_EntityType_NoCompatibleConstructor_PublicParameterlessConstructor_ShouldUsePublicConstructorAndProperties( + bool useAsyncApi + ) { var entities = this.CreateEntitiesInDb(2); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_EntityType_NoMapping_ShouldUseEntityTypeNameAndPropertyNames( - bool useAsyncApi - ) + public async Task QueryFirstOrDefault_EntityType_NoMapping_ShouldUseEntityTypeNameAndPropertyNames(bool useAsyncApi) { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("MappingTestEntity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] @@ -747,9 +806,7 @@ public Task QueryFirstOrDefault_EntityType_NonNullableEntityProperty_ColumnConta bool useAsyncApi ) { - this.Connection.ExecuteNonQuery( - $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)" - ); + this.Connection.ExecuteNonQuery($"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)"); return Invoking(() => CallApi( @@ -759,10 +816,11 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + - $"corresponding property of the type {typeof(Entity)} is non-nullable.*" + "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + + $"corresponding property of the type {typeof(Entity)} is non-nullable.*" ); } @@ -777,13 +835,16 @@ await this.Connection.ExecuteNonQueryAsync( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("NullableBooleanValue")}) VALUES(1, NULL)" ); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("Id")}, {Q("NullableBooleanValue")} FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(new Entity { Id = 1, NullableBooleanValue = null }); + ) + ) + .Should() + .BeEquivalentTo(new Entity { Id = 1, NullableBooleanValue = null }); } [Theory] @@ -795,13 +856,16 @@ public async Task QueryFirstOrDefault_EntityType_ShouldSupportDateTimeOffsetValu var entities = this.CreateEntitiesInDb(2); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("EntityWithDateTimeOffset")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); } [Theory] @@ -821,7 +885,8 @@ public Task QueryFirstOrDefault_EntityType_UnsupportedFieldType_ShouldThrow(bool cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( "The data type System.* of the column 'Value' returned by the SQL statement is not supported.*" ); @@ -834,13 +899,16 @@ public async Task QueryFirstOrDefault_InterpolatedParameter_ShouldPassInterpolat { var entities = this.CreateEntitiesInDb(2); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")} WHERE {Q("Id")} = {Parameter(entities[0].Id)}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); } [Theory] @@ -855,13 +923,16 @@ public async Task QueryFirstOrDefault_Parameter_ShouldPassParameter(bool useAsyn ("Id", entities[0].Id) ); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, statement, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); } [Theory] @@ -869,82 +940,93 @@ public async Task QueryFirstOrDefault_Parameter_ShouldPassParameter(bool useAsyn [InlineData(true)] public async Task QueryFirstOrDefault_QueryReturnedNoRows_ShouldReturnDefault(bool useAsyncApi) { - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("Id")} FROM {Q("Entity")} WHERE {Q("Id")} = -1", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(0); + ) + ) + .Should() + .Be(0); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")} WHERE {Q("Id")} = -1", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeNull(); + ) + ) + .Should() + .BeNull(); - (await CallApi<(long, string)>( + ( + await CallApi<(long, string)>( useAsyncApi, this.Connection, $"SELECT {Q("Id")}, {Q("StringValue")} FROM {Q("Entity")} WHERE {Q("Id")} = -1", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(default); + ) + ) + .Should() + .Be(default); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirstOrDefault_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) + public async Task QueryFirstOrDefault_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entityIds = Generate.Ids(2); - InterpolatedSqlStatement statement = - $"SELECT {Q("Value")} AS {Q("Id")} FROM {TemporaryTable(entityIds)}"; + InterpolatedSqlStatement statement = $"SELECT {Q("Value")} AS {Q("Id")} FROM {TemporaryTable(entityIds)}"; var temporaryTableName = statement.TemporaryTables[0].Name; - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, statement, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(entityIds[0]); + ) + ) + .Should() + .Be(entityIds[0]); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirstOrDefault_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - bool useAsyncApi - ) + public async Task QueryFirstOrDefault_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entities = this.CreateEntitiesInDb(2); var entityIds = entities.ConvertAll(a => a.Id); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $""" - SELECT * - FROM {Q("Entity")} - WHERE {Q("Id")} IN (SELECT {Q("Value")} FROM {TemporaryTable(entityIds)}) - """, + SELECT * + FROM {Q("Entity")} + WHERE {Q("Id")} IN (SELECT {Q("Value")} FROM {TemporaryTable(entityIds)}) + """, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ).Should().BeEquivalentTo(entities[0]); } [Theory] @@ -956,34 +1038,39 @@ public async Task QueryFirstOrDefault_Transaction_ShouldUseTransaction(bool useA { var entities = this.CreateEntitiesInDb(2, transaction); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", transaction, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entities[0]); + ) + ) + .Should() + .BeEquivalentTo(entities[0]); await transaction.RollbackAsync(); } - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeNull(); + ) + ) + .Should() + .BeNull(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirstOrDefault_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthNotOne_ShouldThrow( - bool useAsyncApi - ) + public async Task QueryFirstOrDefault_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthNotOne_ShouldThrow( + bool useAsyncApi + ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) { @@ -997,16 +1084,17 @@ await Invoking(() => cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Value' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Value' returned by the SQL statement contains a value that could not be converted " + + $"to the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } @@ -1018,45 +1106,47 @@ await Invoking(() => cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Value' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Value' returned by the SQL statement contains a value that could not be converted " + + $"to the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirstOrDefault_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - bool useAsyncApi - ) + public async Task QueryFirstOrDefault_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( + bool useAsyncApi + ) { var character = Generate.Single(); - (await CallApi>( + ( + await CallApi>( useAsyncApi, this.Connection, $"SELECT '{character}'", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(ValueTuple.Create(character)); + ) + ) + .Should() + .Be(ValueTuple.Create(character)); } [Theory] [InlineData(false)] [InlineData(true)] - public Task - QueryFirstOrDefault_ValueTupleType_ColumnDataTypeNotCompatibleWithValueTupleFieldType_ShouldThrow( - bool useAsyncApi - ) => + public Task QueryFirstOrDefault_ValueTupleType_ColumnDataTypeNotCompatibleWithValueTupleFieldType_ShouldThrow( + bool useAsyncApi + ) => Invoking(() => CallApi>( useAsyncApi, @@ -1065,20 +1155,20 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The data type System.* of the column 'Value' returned by the SQL statement is not compatible with " + - $"the field type {typeof(TimeSpan)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}.*" + "The data type System.* of the column 'Value' returned by the SQL statement is not compatible with " + + $"the field type {typeof(TimeSpan)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}.*" ); [Theory] [InlineData(false)] [InlineData(true)] - public Task - QueryFirstOrDefault_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidInteger_ShouldThrow( - bool useAsyncApi - ) => + public Task QueryFirstOrDefault_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidInteger_ShouldThrow( + bool useAsyncApi + ) => Invoking(() => CallApi>( useAsyncApi, @@ -1087,16 +1177,17 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Value' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Value' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - "Could not convert the value '999*' (System.*) to an enum member of the type " + - $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" + "Could not convert the value '999*' (System.*) to an enum member of the type " + + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); [Theory] @@ -1113,16 +1204,17 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Value' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Value' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + - "That string does not match any of the names of the enum's members.*" + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + + "That string does not match any of the names of the enum's members.*" ); [Theory] @@ -1134,31 +1226,35 @@ bool useAsyncApi { var enumValue = Generate.Single(); - (await CallApi>( + ( + await CallApi>( useAsyncApi, this.Connection, $"SELECT {(int)enumValue}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(ValueTuple.Create(enumValue)); + ) + ) + .Should() + .Be(ValueTuple.Create(enumValue)); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirstOrDefault_ValueTupleType_EnumValueTupleField_ShouldConvertStringToEnum( - bool useAsyncApi - ) + public async Task QueryFirstOrDefault_ValueTupleType_EnumValueTupleField_ShouldConvertStringToEnum(bool useAsyncApi) { var enumValue = Generate.Single(); - (await CallApi>( + ( + await CallApi>( useAsyncApi, this.Connection, $"SELECT '{enumValue}'", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(ValueTuple.Create(enumValue)); + ) + ) + .Should() + .Be(ValueTuple.Create(enumValue)); } [Theory] @@ -1168,9 +1264,7 @@ public Task QueryFirstOrDefault_ValueTupleType_NonNullableValueTupleField_Column bool useAsyncApi ) { - this.Connection.ExecuteNonQuery( - $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)" - ); + this.Connection.ExecuteNonQuery($"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)"); return Invoking(() => CallApi>( @@ -1180,41 +1274,43 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + - $"corresponding field of the value tuple type {typeof(ValueTuple)} is non-nullable.*" + "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + + $"corresponding field of the value tuple type {typeof(ValueTuple)} is non-nullable.*" ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirstOrDefault_ValueTupleType_NullableValueTupleField_ColumnContainsNull_ShouldReturnNull( - bool useAsyncApi - ) + public async Task QueryFirstOrDefault_ValueTupleType_NullableValueTupleField_ColumnContainsNull_ShouldReturnNull( + bool useAsyncApi + ) { await this.Connection.ExecuteNonQueryAsync( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("NullableBooleanValue")}) VALUES(1, NULL)" ); - (await CallApi>( + ( + await CallApi>( useAsyncApi, this.Connection, $"SELECT {Q("NullableBooleanValue")} FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(new(null)); + ) + ) + .Should() + .Be(new(null)); } [Theory] [InlineData(false)] [InlineData(true)] - public Task - QueryFirstOrDefault_ValueTupleType_NumberOfColumnsDoesNotMatchNumberOfValueTupleFields_ShouldThrow( - bool useAsyncApi - ) => + public Task QueryFirstOrDefault_ValueTupleType_NumberOfColumnsDoesNotMatchNumberOfValueTupleFields_ShouldThrow( + bool useAsyncApi + ) => Invoking(() => CallApi<(int, int)>( useAsyncApi, @@ -1223,11 +1319,12 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The SQL statement returned 1 column, but the value tuple type {typeof((int, int))} has 2 " + - "fields. Make sure that the SQL statement returns the same number of columns as the number of " + - "fields in the value tuple type.*" + $"The SQL statement returned 1 column, but the value tuple type {typeof((int, int))} has 2 " + + "fields. Make sure that the SQL statement returns the same number of columns as the number of " + + "fields in the value tuple type.*" ); [Theory] @@ -1237,13 +1334,16 @@ public async Task QueryFirstOrDefault_ValueTupleType_ShouldMaterializeBinaryData { var bytes = Generate.Single(); - (await CallApi>( + ( + await CallApi>( useAsyncApi, this.Connection, $"SELECT {Parameter(bytes)} AS BinaryData", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(ValueTuple.Create(bytes)); + ) + ) + .Should() + .BeEquivalentTo(ValueTuple.Create(bytes)); } [Theory] @@ -1255,13 +1355,16 @@ public async Task QueryFirstOrDefault_ValueTupleType_ShouldSupportDateTimeOffset var entities = this.CreateEntitiesInDb(2); - (await CallApi<(long Id, DateTimeOffset DateTimeOffsetValue)>( + ( + await CallApi<(long Id, DateTimeOffset DateTimeOffsetValue)>( useAsyncApi, this.Connection, $"SELECT {Q("Id")}, {Q("DateTimeOffsetValue")} FROM {Q("EntityWithDateTimeOffset")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be((entities[0].Id, entities[0].DateTimeOffsetValue)); + ) + ) + .Should() + .Be((entities[0].Id, entities[0].DateTimeOffsetValue)); } [Theory] @@ -1281,7 +1384,8 @@ public Task QueryFirstOrDefault_ValueTupleType_UnsupportedFieldType_ShouldThrow( cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( "The data type System.* of the column 'Value' returned by the SQL statement is not supported.*" ); diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOrDefaultTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOrDefaultTests.cs index 732b516..720523d 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOrDefaultTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstOrDefaultTests.cs @@ -4,28 +4,23 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests; -public sealed class - DbConnectionExtensions_QueryFirstOrDefaultTests_MySql : - DbConnectionExtensions_QueryFirstOrDefaultTests; +public sealed class DbConnectionExtensions_QueryFirstOrDefaultTests_MySql + : DbConnectionExtensions_QueryFirstOrDefaultTests; -public sealed class - DbConnectionExtensions_QueryFirstOrDefaultTests_Oracle : - DbConnectionExtensions_QueryFirstOrDefaultTests; +public sealed class DbConnectionExtensions_QueryFirstOrDefaultTests_Oracle + : DbConnectionExtensions_QueryFirstOrDefaultTests; -public sealed class - DbConnectionExtensions_QueryFirstOrDefaultTests_PostgreSql : - DbConnectionExtensions_QueryFirstOrDefaultTests; +public sealed class DbConnectionExtensions_QueryFirstOrDefaultTests_PostgreSql + : DbConnectionExtensions_QueryFirstOrDefaultTests; -public sealed class - DbConnectionExtensions_QueryFirstOrDefaultTests_Sqlite : - DbConnectionExtensions_QueryFirstOrDefaultTests; +public sealed class DbConnectionExtensions_QueryFirstOrDefaultTests_Sqlite + : DbConnectionExtensions_QueryFirstOrDefaultTests; -public sealed class - DbConnectionExtensions_QueryFirstOrDefaultTests_SqlServer : - DbConnectionExtensions_QueryFirstOrDefaultTests; +public sealed class DbConnectionExtensions_QueryFirstOrDefaultTests_SqlServer + : DbConnectionExtensions_QueryFirstOrDefaultTests; -public abstract class - DbConnectionExtensions_QueryFirstOrDefaultTests : IntegrationTestsBase +public abstract class DbConnectionExtensions_QueryFirstOrDefaultTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { [Theory] @@ -49,7 +44,8 @@ await Invoking(() => cancellationToken: cancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); } @@ -97,17 +93,15 @@ bool useAsyncApi EntityAssertions.AssertDataRowMatchesEntity(dataRow!, entities[0]); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirstOrDefault_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - bool useAsyncApi - ) + public async Task QueryFirstOrDefault_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -162,18 +156,21 @@ public async Task QueryFirstOrDefault_Parameter_ShouldPassParameter(bool useAsyn EntityAssertions.AssertDataRowMatchesEntity(dataRow!, entities[0]); } - [Theory] [InlineData(false)] [InlineData(true)] public async Task QueryFirstOrDefault_QueryReturnedNoRows_ShouldReturnNull(bool useAsyncApi) => - ((object?)await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("Entity")} WHERE {Q("Id")} = -1", - cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeNull(); + ( + (object?) + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("Entity")} WHERE {Q("Id")} = -1", + cancellationToken: TestContext.Current.CancellationToken + ) + ) + .Should() + .BeNull(); [Theory] [InlineData(false)] @@ -197,23 +194,19 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ); - dataRow - .Should().NotBeNull(); + dataRow.Should().NotBeNull(); - dataRow["Id"] - .Should().Be(entityIds[0]); + dataRow["Id"].Should().Be(entityIds[0]); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirstOrDefault_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - bool useAsyncApi - ) + public async Task QueryFirstOrDefault_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -226,8 +219,7 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ); - ValueConverter.ConvertValueToType(dataRow!["Id"]) - .Should().Be(entityIds[0]); + ValueConverter.ConvertValueToType(dataRow!["Id"]).Should().Be(entityIds[0]); } [Theory] @@ -269,13 +261,17 @@ public async Task QueryFirstOrDefault_Transaction_ShouldUseTransaction(bool useA await transaction.RollbackAsync(); } - ((object?)await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("Entity")}", - cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeNull(); + ( + (object?) + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("Entity")}", + cancellationToken: TestContext.Current.CancellationToken + ) + ) + .Should() + .BeNull(); } private static Task CallApi( @@ -302,13 +298,7 @@ public async Task QueryFirstOrDefault_Transaction_ShouldUseTransaction(bool useA try { return Task.FromResult( - connection.QueryFirstOrDefault( - statement, - transaction, - commandTimeout, - commandType, - cancellationToken - ) + connection.QueryFirstOrDefault(statement, transaction, commandTimeout, commandType, cancellationToken) ); } catch (Exception ex) diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstTests.cs index b249da4..86f5fa2 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryFirstTests.cs @@ -4,28 +4,23 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests; -public sealed class - DbConnectionExtensions_QueryFirstTests_MySql : - DbConnectionExtensions_QueryFirstTests; +public sealed class DbConnectionExtensions_QueryFirstTests_MySql + : DbConnectionExtensions_QueryFirstTests; -public sealed class - DbConnectionExtensions_QueryFirstTests_Oracle : - DbConnectionExtensions_QueryFirstTests; +public sealed class DbConnectionExtensions_QueryFirstTests_Oracle + : DbConnectionExtensions_QueryFirstTests; -public sealed class - DbConnectionExtensions_QueryFirstTests_PostgreSql : - DbConnectionExtensions_QueryFirstTests; +public sealed class DbConnectionExtensions_QueryFirstTests_PostgreSql + : DbConnectionExtensions_QueryFirstTests; -public sealed class - DbConnectionExtensions_QueryFirstTests_Sqlite : - DbConnectionExtensions_QueryFirstTests; +public sealed class DbConnectionExtensions_QueryFirstTests_Sqlite + : DbConnectionExtensions_QueryFirstTests; -public sealed class - DbConnectionExtensions_QueryFirstTests_SqlServer : - DbConnectionExtensions_QueryFirstTests; +public sealed class DbConnectionExtensions_QueryFirstTests_SqlServer + : DbConnectionExtensions_QueryFirstTests; -public abstract class - DbConnectionExtensions_QueryFirstTests : IntegrationTestsBase +public abstract class DbConnectionExtensions_QueryFirstTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { [Theory] @@ -47,7 +42,8 @@ await Invoking(() => cancellationToken: cancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); } @@ -74,9 +70,7 @@ public async Task QueryFirst_CommandType_ShouldUseCommandType(bool useAsyncApi) [Theory] [InlineData(false)] [InlineData(true)] - public async Task QueryFirst_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution( - bool useAsyncApi - ) + public async Task QueryFirst_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -95,17 +89,15 @@ bool useAsyncApi EntityAssertions.AssertDataRowMatchesEntity(dataRow, entities[0]); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirst_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - bool useAsyncApi - ) + public async Task QueryFirst_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -160,22 +152,21 @@ public async Task QueryFirst_Parameter_ShouldPassParameter(bool useAsyncApi) EntityAssertions.AssertDataRowMatchesEntity(dataRow, entities[0]); } - [Theory] [InlineData(false)] [InlineData(true)] public Task QueryFirst_QueryReturnedNoRows_ShouldThrow(bool useAsyncApi) => - Invoking(() => CallApi( + Invoking(() => + CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")} WHERE {Q("Id")} = -1", cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() - .WithMessage( - "The SQL statement did not return any rows." - ); + .Should() + .ThrowAsync() + .WithMessage("The SQL statement did not return any rows."); [Theory] [InlineData(false)] @@ -197,23 +188,19 @@ public async Task QueryFirst_ScalarValuesTemporaryTable_ShouldDropTemporaryTable cancellationToken: TestContext.Current.CancellationToken ); - dataRow - .Should().NotBeNull(); + dataRow.Should().NotBeNull(); - dataRow["Id"] - .Should().Be(entityIds[0]); + dataRow["Id"].Should().Be(entityIds[0]); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QueryFirst_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - bool useAsyncApi - ) + public async Task QueryFirst_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -226,8 +213,7 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ); - ValueConverter.ConvertValueToType(dataRow["Id"]) - .Should().Be(entityIds[0]); + ValueConverter.ConvertValueToType(dataRow["Id"]).Should().Be(entityIds[0]); } [Theory] @@ -269,17 +255,17 @@ public async Task QueryFirst_Transaction_ShouldUseTransaction(bool useAsyncApi) await transaction.RollbackAsync(); } - await Invoking(() => CallApi( + await Invoking(() => + CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() - .WithMessage( - "The SQL statement did not return any rows." - ); + .Should() + .ThrowAsync() + .WithMessage("The SQL statement did not return any rows."); } private static Task CallApi( @@ -294,25 +280,13 @@ private static Task CallApi( { if (useAsyncApi) { - return connection.QueryFirstAsync( - statement, - transaction, - commandTimeout, - commandType, - cancellationToken - ); + return connection.QueryFirstAsync(statement, transaction, commandTimeout, commandType, cancellationToken); } try { return Task.FromResult( - connection.QueryFirst( - statement, - transaction, - commandTimeout, - commandType, - cancellationToken - ) + connection.QueryFirst(statement, transaction, commandTimeout, commandType, cancellationToken) ); } catch (Exception ex) diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryOfTTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryOfTTests.cs index e5ea63d..1ff9edc 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryOfTTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryOfTTests.cs @@ -2,28 +2,23 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests; -public sealed class - DbConnectionExtensions_QueryOfTTests_MySql : - DbConnectionExtensions_QueryOfTTests; +public sealed class DbConnectionExtensions_QueryOfTTests_MySql + : DbConnectionExtensions_QueryOfTTests; -public sealed class - DbConnectionExtensions_QueryOfTTests_Oracle : - DbConnectionExtensions_QueryOfTTests; +public sealed class DbConnectionExtensions_QueryOfTTests_Oracle + : DbConnectionExtensions_QueryOfTTests; -public sealed class - DbConnectionExtensions_QueryOfTTests_PostgreSql : - DbConnectionExtensions_QueryOfTTests; +public sealed class DbConnectionExtensions_QueryOfTTests_PostgreSql + : DbConnectionExtensions_QueryOfTTests; -public sealed class - DbConnectionExtensions_QueryOfTTests_Sqlite : - DbConnectionExtensions_QueryOfTTests; +public sealed class DbConnectionExtensions_QueryOfTTests_Sqlite + : DbConnectionExtensions_QueryOfTTests; -public sealed class - DbConnectionExtensions_QueryOfTTests_SqlServer : - DbConnectionExtensions_QueryOfTTests; +public sealed class DbConnectionExtensions_QueryOfTTests_SqlServer + : DbConnectionExtensions_QueryOfTTests; -public abstract class - DbConnectionExtensions_QueryOfTTests : IntegrationTestsBase +public abstract class DbConnectionExtensions_QueryOfTTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { [Theory] @@ -37,43 +32,53 @@ bool useAsyncApi { // Oracle doesn't allow to return an empty string, because it treats empty strings as NULLs. - (await Invoking(() => + ( + await Invoking(() => CallApi( - useAsyncApi, - this.Connection, - "SELECT ''", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + useAsyncApi, + this.Connection, + "SELECT ''", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value '' ({typeof(string)}), " + - $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" - )) + $"The first column returned by the SQL statement contains the value '' ({typeof(string)}), " + + $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" + ) + ) .WithInnerException() .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly " + - "one character long." + $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly " + + "one character long." ); } - (await Invoking(() => + ( + await Invoking(() => CallApi( - useAsyncApi, - this.Connection, - "SELECT 'ab'", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + useAsyncApi, + this.Connection, + "SELECT 'ab'", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value 'ab' ({typeof(string)}), " + - $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" - )) + $"The first column returned by the SQL statement contains the value 'ab' ({typeof(string)}), " + + $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" + ) + ) .WithInnerException() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + - "one character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + + "one character long." ); } @@ -86,13 +91,17 @@ bool useAsyncApi { var character = Generate.Single(); - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT '{character}'", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo([character]); + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT '{character}'", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo([character]); } [Theory] @@ -101,16 +110,19 @@ bool useAsyncApi public Task Query_BuiltInType_ColumnValueCannotBeConvertedToTargetType_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi( - useAsyncApi, - this.Connection, - "SELECT 'A'", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + useAsyncApi, + this.Connection, + "SELECT 'A'", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value 'A' ({typeof(string)}), which " + - $"could not be converted to the type {typeof(int)}. See inner exception for details.*" + $"The first column returned by the SQL statement contains the value 'A' ({typeof(string)}), which " + + $"could not be converted to the type {typeof(int)}. See inner exception for details.*" ); [Theory] @@ -119,16 +131,19 @@ public Task Query_BuiltInType_ColumnValueCannotBeConvertedToTargetType_ShouldThr public Task Query_BuiltInType_EnumTargetType_ColumnContainsInvalidInteger_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi( - useAsyncApi, - this.Connection, - "SELECT 999", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + useAsyncApi, + this.Connection, + "SELECT 999", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column returned by the SQL statement contains the value '999*' (System.*), which " + - $"could not be converted to the type {typeof(TestEnum)}. See inner exception for details.*" + "The first column returned by the SQL statement contains the value '999*' (System.*), which " + + $"could not be converted to the type {typeof(TestEnum)}. See inner exception for details.*" ); [Theory] @@ -137,17 +152,20 @@ public Task Query_BuiltInType_EnumTargetType_ColumnContainsInvalidInteger_Should public Task Query_BuiltInType_EnumTargetType_ColumnContainsInvalidString_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi( - useAsyncApi, - this.Connection, - "SELECT 'NonExistent'", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + useAsyncApi, + this.Connection, + "SELECT 'NonExistent'", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column returned by the SQL statement contains the value 'NonExistent' " + - $"({typeof(string)}), which could not be converted to the type {typeof(TestEnum)}. See inner " + - "exception for details.*" + "The first column returned by the SQL statement contains the value 'NonExistent' " + + $"({typeof(string)}), which could not be converted to the type {typeof(TestEnum)}. See inner " + + "exception for details.*" ); [Theory] @@ -157,13 +175,17 @@ public async Task Query_BuiltInType_EnumTargetType_ShouldConvertIntegerToEnum(bo { var enumValue = Generate.Single(); - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT {(int)enumValue}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo([enumValue]); + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT {(int)enumValue}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo([enumValue]); } [Theory] @@ -173,13 +195,17 @@ public async Task Query_BuiltInType_EnumTargetType_ShouldConvertStringToEnum(boo { var enumValue = Generate.Single(); - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT '{enumValue.ToString()}'", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo([enumValue]); + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT '{enumValue.ToString()}'", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo([enumValue]); } [Theory] @@ -188,30 +214,37 @@ public async Task Query_BuiltInType_EnumTargetType_ShouldConvertStringToEnum(boo public Task Query_BuiltInType_NonNullableTargetType_ColumnContainsNull_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi( - useAsyncApi, - this.Connection, - "SELECT NULL", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + useAsyncApi, + this.Connection, + "SELECT NULL", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column returned by the SQL statement contains a NULL value, which could not be converted " + - $"to the type {typeof(int)}. See inner exception for details.*" + "The first column returned by the SQL statement contains a NULL value, which could not be converted " + + $"to the type {typeof(int)}. See inner exception for details.*" ); [Theory] [InlineData(false)] [InlineData(true)] - public async Task - Query_BuiltInType_NullableTargetType_ColumnContainsNull_ShouldReturnNull(bool useAsyncApi) => - (await CallApi( - useAsyncApi, - this.Connection, - "SELECT NULL", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask()) - .Should().BeEquivalentTo(new int?[] { null }); + public async Task Query_BuiltInType_NullableTargetType_ColumnContainsNull_ShouldReturnNull(bool useAsyncApi) => + ( + await CallApi( + useAsyncApi, + this.Connection, + "SELECT NULL", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() + ) + .Should() + .BeEquivalentTo(new int?[] { null }); [Theory] [InlineData(false)] @@ -222,13 +255,17 @@ public async Task Query_BuiltInType_ShouldSupportDateTimeOffsetValues(bool useAs var entities = this.CreateEntitiesInDb(); - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT {Q("DateTimeOffsetValue")} FROM {Q("EntityWithDateTimeOffset")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities.Select(e => e.DateTimeOffsetValue)); + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT {Q("DateTimeOffsetValue")} FROM {Q("EntityWithDateTimeOffset")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities.Select(e => e.DateTimeOffsetValue)); } [Theory] @@ -244,13 +281,16 @@ public async Task Query_CancellationToken_ShouldCancelOperationIfCancellationIsR await Invoking(() => CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("Entity")}", - cancellationToken: cancellationToken - ).ToListAsync(cancellationToken).AsTask() + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("Entity")}", + cancellationToken: cancellationToken + ) + .ToListAsync(cancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); } @@ -263,21 +303,26 @@ public async Task Query_CommandType_ShouldUseCommandType(bool useAsyncApi) var entities = this.CreateEntitiesInDb(); - (await CallApi( - useAsyncApi, - this.Connection, - "GetEntities", - commandType: CommandType.StoredProcedure, - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities); + ( + await CallApi( + useAsyncApi, + this.Connection, + "GetEntities", + commandType: CommandType.StoredProcedure, + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - Query_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterEnumerationIsFinished(bool useAsyncApi) + public async Task Query_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterEnumerationIsFinished( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -288,57 +333,59 @@ public async Task var temporaryTableName = statement.TemporaryTables[0].Name; var asyncEnumerator = CallApi( - useAsyncApi, - this.Connection, - statement, - cancellationToken: TestContext.Current.CancellationToken - ).GetAsyncEnumerator(); + useAsyncApi, + this.Connection, + statement, + cancellationToken: TestContext.Current.CancellationToken + ) + .GetAsyncEnumerator(); - (await asyncEnumerator.MoveNextAsync()) - .Should().BeTrue(); + (await asyncEnumerator.MoveNextAsync()).Should().BeTrue(); if (this.TestDatabaseProvider.SupportsCommandExecutionWhileDataReaderIsOpen) { - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeTrue(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeTrue(); } - (await asyncEnumerator.MoveNextAsync()) - .Should().BeTrue(); + (await asyncEnumerator.MoveNextAsync()).Should().BeTrue(); - (await asyncEnumerator.MoveNextAsync()) - .Should().BeFalse(); + (await asyncEnumerator.MoveNextAsync()).Should().BeFalse(); await asyncEnumerator.DisposeAsync(); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - Query_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable(bool useAsyncApi) + public async Task Query_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entities = Generate.Multiple(); - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {TemporaryTable(entities)}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities); + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT * FROM {TemporaryTable(entities)}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - Query_EntityType_CharEntityProperty_ColumnContainsStringWithLengthNotOne_ShouldThrow(bool useAsyncApi) + public async Task Query_EntityType_CharEntityProperty_ColumnContainsStringWithLengthNotOne_ShouldThrow( + bool useAsyncApi + ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) { @@ -346,63 +393,72 @@ public async Task await Invoking(() => CallApi( - useAsyncApi, - this.Connection, - $"SELECT '' AS {Q("CharValue")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + useAsyncApi, + this.Connection, + $"SELECT '' AS {Q("CharValue")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'CharValue' returned by the SQL statement contains a value that could not be " + - $"converted to the type {typeof(char)} of the corresponding property of the type " + - $"{typeof(Entity)}. See inner exception for details.*" + "The column 'CharValue' returned by the SQL statement contains a value that could not be " + + $"converted to the type {typeof(char)} of the corresponding property of the type " + + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } await Invoking(() => CallApi( - useAsyncApi, - this.Connection, - $"SELECT 'ab' AS {Q("CharValue")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + useAsyncApi, + this.Connection, + $"SELECT 'ab' AS {Q("CharValue")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(char)} of the corresponding property of the type " + - $"{typeof(Entity)}. See inner exception for details.*" + "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + + $"to the type {typeof(char)} of the corresponding property of the type " + + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - Query_EntityType_CharEntityProperty_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - bool useAsyncApi - ) + public async Task Query_EntityType_CharEntityProperty_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( + bool useAsyncApi + ) { var character = Generate.Single(); - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT '{character}' AS {Q("CharValue")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo([new Entity { CharValue = character }]); + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT '{character}' AS {Q("CharValue")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo([new Entity { CharValue = character }]); } [Theory] @@ -411,17 +467,20 @@ bool useAsyncApi public Task Query_EntityType_ColumnDataTypeNotCompatibleWithEntityPropertyType_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi( - useAsyncApi, - this.Connection, - $"SELECT 123 AS {Q("TimeSpanValue")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + useAsyncApi, + this.Connection, + $"SELECT 123 AS {Q("TimeSpanValue")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The data type System.* of the column 'TimeSpanValue' returned by the SQL statement is not " + - $"compatible with the property type {typeof(TimeSpan)} of the corresponding property of the type " + - $"{typeof(Entity)}.*" + "The data type System.* of the column 'TimeSpanValue' returned by the SQL statement is not " + + $"compatible with the property type {typeof(TimeSpan)} of the corresponding property of the type " + + $"{typeof(Entity)}.*" ); [Theory] @@ -431,28 +490,28 @@ public async Task Query_EntityType_ColumnHasNoName_ShouldThrow(bool useAsyncApi) { InterpolatedSqlStatement statement = this.TestDatabaseProvider switch { - SqlServerTestDatabaseProvider => - "SELECT 1", + SqlServerTestDatabaseProvider => "SELECT 1", - PostgreSqlTestDatabaseProvider or OracleTestDatabaseProvider => - "SELECT 1 AS \" \"", + PostgreSqlTestDatabaseProvider or OracleTestDatabaseProvider => "SELECT 1 AS \" \"", - _ => - "SELECT 1 AS ''" + _ => "SELECT 1 AS ''", }; await Invoking(() => CallApi( - useAsyncApi, - this.Connection, - statement, - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + useAsyncApi, + this.Connection, + statement, + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The 1st column returned by the SQL statement does not have a name. Make sure that all columns the " + - "statement returns have a name.*" + "The 1st column returned by the SQL statement does not have a name. Make sure that all columns the " + + "statement returns have a name.*" ); } @@ -463,13 +522,17 @@ public async Task Query_EntityType_CompatiblePrivateConstructor_ShouldUsePrivate { var entities = this.CreateEntitiesInDb(); - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("Entity")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities); + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("Entity")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities); } [Theory] @@ -479,13 +542,17 @@ public async Task Query_EntityType_CompatiblePublicConstructor_ShouldUsePublicCo { var entities = this.CreateEntitiesInDb(); - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("Entity")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities); + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("Entity")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities); } [Theory] @@ -495,18 +562,22 @@ public async Task Query_EntityType_EntityTypeHasNoCorrespondingPropertyForColumn bool useAsyncApi ) { - var entities = (await Invoking(() => - CallApi( - useAsyncApi, - this.Connection, - $"SELECT 1 AS {Q("Id")}, 2 AS {Q("Int32Value")}, 3 AS {Q("NonExistent")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() - ) - .Should().NotThrowAsync()).Subject; + var entities = ( + await Invoking(() => + CallApi( + useAsyncApi, + this.Connection, + $"SELECT 1 AS {Q("Id")}, 2 AS {Q("Int32Value")}, 3 AS {Q("NonExistent")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() + ) + .Should() + .NotThrowAsync() + ).Subject; - entities - .Should().BeEquivalentTo([new Entity { Id = 1, Int32Value = 2 }]); + entities.Should().BeEquivalentTo([new Entity { Id = 1, Int32Value = 2 }]); } [Theory] @@ -519,63 +590,71 @@ bool useAsyncApi var entities = this.CreateEntitiesInDb(); var entitiesWithDifferentCasingProperties = Generate.MapTo(entities); - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("Entity")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entitiesWithDifferentCasingProperties); + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("Entity")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entitiesWithDifferentCasingProperties); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_EntityType_EnumEntityProperty_ColumnContainsInvalidInteger_ShouldThrow( - bool useAsyncApi - ) => - await Invoking(() => CallApi( - useAsyncApi, - this.Connection, - $"SELECT 1 AS {Q("Id")}, 999 AS {Q("Enum")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + public async Task Query_EntityType_EnumEntityProperty_ColumnContainsInvalidInteger_ShouldThrow(bool useAsyncApi) => + await Invoking(() => + CallApi( + useAsyncApi, + this.Connection, + $"SELECT 1 AS {Q("Id")}, 999 AS {Q("Enum")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding property of the type " + - $"{typeof(EntityWithEnumStoredAsInteger)}. See inner exception for details.*" + "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding property of the type " + + $"{typeof(EntityWithEnumStoredAsInteger)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - "Could not convert the value '999*' (System.*) to an enum member of the type " + - $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" + "Could not convert the value '999*' (System.*) to an enum member of the type " + + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_EntityType_EnumEntityProperty_ColumnContainsInvalidString_ShouldThrow( - bool useAsyncApi - ) => - await Invoking(() => CallApi( - useAsyncApi, - this.Connection, - $"SELECT 1 AS {Q("Id")}, 'NonExistent' AS {Q("Enum")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + public async Task Query_EntityType_EnumEntityProperty_ColumnContainsInvalidString_ShouldThrow(bool useAsyncApi) => + await Invoking(() => + CallApi( + useAsyncApi, + this.Connection, + $"SELECT 1 AS {Q("Id")}, 'NonExistent' AS {Q("Enum")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding property of the type " + - $"{typeof(EntityWithEnumStoredAsString)}. See inner exception for details.*" + "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding property of the type " + + $"{typeof(EntityWithEnumStoredAsString)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + - "That string does not match any of the names of the enum's members.*" + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + + "That string does not match any of the names of the enum's members.*" ); [Theory] @@ -585,14 +664,17 @@ public async Task Query_EntityType_EnumEntityProperty_ShouldConvertIntegerToEnum { var enumValue = Generate.Single(); - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT 1 AS {Q("Id")}, {(int)enumValue} AS {Q("Enum")}", - cancellationToken: TestContext.Current.CancellationToken - ).FirstAsync()) - .Enum - .Should().Be(enumValue); + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT 1 AS {Q("Id")}, {(int)enumValue} AS {Q("Enum")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .FirstAsync() + ) + .Enum.Should() + .Be(enumValue); } [Theory] @@ -602,14 +684,17 @@ public async Task Query_EntityType_EnumEntityProperty_ShouldConvertStringToEnum( { var enumValue = Generate.Single(); - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT 1 AS {Q("Id")}, '{enumValue.ToString()}' AS {Q("Enum")}", - cancellationToken: TestContext.Current.CancellationToken - ).FirstAsync()) - .Enum - .Should().Be(enumValue); + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT 1 AS {Q("Id")}, '{enumValue.ToString()}' AS {Q("Enum")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .FirstAsync() + ) + .Enum.Should() + .Be(enumValue); } [Theory] @@ -619,16 +704,22 @@ public async Task Query_EntityType_Mapping_Attributes_ShouldUseAttributesMapping { var entities = this.CreateEntitiesInDb(); - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("MappingTestEntity")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo( + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("MappingTestEntity")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo( entities, - options => options.Using(context => context.Subject.Should().BeNull()) - .When(info => info.Path.EndsWith("NotMapped")) + options => + options + .Using(context => context.Subject.Should().BeNull()) + .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -641,16 +732,22 @@ public async Task Query_EntityType_Mapping_FluentApi_ShouldUseFluentApiMapping(b var entities = this.CreateEntitiesInDb(); - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("MappingTestEntity")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo( + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("MappingTestEntity")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo( entities, - options => options.Using(context => context.Subject.Should().BeNull()) - .When(info => info.Path.EndsWith("NotMapped")) + options => + options + .Using(context => context.Subject.Should().BeNull()) + .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -661,13 +758,17 @@ public async Task Query_EntityType_Mapping_NoMapping_ShouldUseEntityTypeNameAndP { var entities = this.CreateEntitiesInDb(); - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("MappingTestEntity")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities); + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("MappingTestEntity")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities); } [Theory] @@ -676,53 +777,61 @@ public async Task Query_EntityType_Mapping_NoMapping_ShouldUseEntityTypeNameAndP public Task Query_EntityType_NoCompatibleConstructor_NoParameterlessConstructor_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi(useAsyncApi, this.Connection, $"SELECT 1 AS {Q("NonExistent")}") - .ToListAsync(TestContext.Current.CancellationToken).AsTask() + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"Could not materialize an instance of the type {typeof(EntityWithPublicConstructor)}. The type " + - "either needs to have a parameterless constructor or a constructor whose parameters match the " + - "columns returned by the SQL statement, e.g. a constructor that has the following " + - $"signature:{Environment.NewLine}" + - "(* NonExistent).*" + $"Could not materialize an instance of the type {typeof(EntityWithPublicConstructor)}. The type " + + "either needs to have a parameterless constructor or a constructor whose parameters match the " + + "columns returned by the SQL statement, e.g. a constructor that has the following " + + $"signature:{Environment.NewLine}" + + "(* NonExistent).*" ); [Theory] [InlineData(false)] [InlineData(true)] - public async Task - Query_EntityType_NoCompatibleConstructor_PrivateParameterlessConstructor_ShouldUsePrivateConstructorAndProperties( - bool useAsyncApi - ) + public async Task Query_EntityType_NoCompatibleConstructor_PrivateParameterlessConstructor_ShouldUsePrivateConstructorAndProperties( + bool useAsyncApi + ) { var entities = this.CreateEntitiesInDb(); - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("Entity")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities); + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("Entity")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - Query_EntityType_NoCompatibleConstructor_PublicParameterlessConstructor_ShouldUsePublicConstructorAndProperties( - bool useAsyncApi - ) + public async Task Query_EntityType_NoCompatibleConstructor_PublicParameterlessConstructor_ShouldUsePublicConstructorAndProperties( + bool useAsyncApi + ) { var entities = this.CreateEntitiesInDb(); - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("Entity")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities); + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("Entity")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities); } [Theory] @@ -730,22 +839,23 @@ bool useAsyncApi [InlineData(true)] public Task Query_EntityType_NonNullableEntityProperty_ColumnContainsNull_ShouldThrow(bool useAsyncApi) { - this.Connection.ExecuteNonQuery( - $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)" - ); + this.Connection.ExecuteNonQuery($"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)"); return Invoking(() => CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("Entity")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("Entity")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + - $"corresponding property of the type {typeof(Entity)} is non-nullable.*" + "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + + $"corresponding property of the type {typeof(Entity)} is non-nullable.*" ); } @@ -758,13 +868,17 @@ await this.Connection.ExecuteNonQueryAsync( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("NullableBooleanValue")}) VALUES(1, NULL)" ); - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT {Q("Id")}, {Q("NullableBooleanValue")} FROM {Q("Entity")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo([new Entity { Id = 1, NullableBooleanValue = null }]); + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT {Q("Id")}, {Q("NullableBooleanValue")} FROM {Q("Entity")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo([new Entity { Id = 1, NullableBooleanValue = null }]); } [Theory] @@ -776,13 +890,17 @@ public async Task Query_EntityType_ShouldSupportDateTimeOffsetValues(bool useAsy var entities = this.CreateEntitiesInDb(); - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("EntityWithDateTimeOffset")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities); + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("EntityWithDateTimeOffset")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities); } [Theory] @@ -796,13 +914,16 @@ public Task Query_EntityType_UnsupportedFieldType_ShouldThrow(bool useAsyncApi) return Invoking(() => CallApi( - useAsyncApi, - this.Connection, - $"SELECT {literal} AS {Q("Value")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + useAsyncApi, + this.Connection, + $"SELECT {literal} AS {Q("Value")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( "The data type System.* of the column 'Value' returned by the SQL statement is not supported.*" ); @@ -815,13 +936,17 @@ public async Task Query_InterpolatedParameter_ShouldPassInterpolatedParameter(bo { var entity = this.CreateEntityInDb(); - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("Entity")} WHERE {Q("Id")} = {Parameter(entity.Id)}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo([entity]); + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("Entity")} WHERE {Q("Id")} = {Parameter(entity.Id)}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo([entity]); } [Theory] @@ -836,80 +961,83 @@ public async Task Query_Parameter_ShouldPassParameter(bool useAsyncApi) ("Id", entity.Id) ); - (await CallApi( - useAsyncApi, - this.Connection, - statement, - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo([entity]); + ( + await CallApi( + useAsyncApi, + this.Connection, + statement, + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo([entity]); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - Query_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterEnumerationIsFinished(bool useAsyncApi) + public async Task Query_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterEnumerationIsFinished( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entityIds = Generate.Ids(2); - InterpolatedSqlStatement statement = - $"SELECT {Q("Value")} AS {Q("Id")} FROM {TemporaryTable(entityIds)}"; + InterpolatedSqlStatement statement = $"SELECT {Q("Value")} AS {Q("Id")} FROM {TemporaryTable(entityIds)}"; var temporaryTableName = statement.TemporaryTables[0].Name; var asyncEnumerator = CallApi( - useAsyncApi, - this.Connection, - statement, - cancellationToken: TestContext.Current.CancellationToken - ).GetAsyncEnumerator(); + useAsyncApi, + this.Connection, + statement, + cancellationToken: TestContext.Current.CancellationToken + ) + .GetAsyncEnumerator(); - (await asyncEnumerator.MoveNextAsync()) - .Should().BeTrue(); + (await asyncEnumerator.MoveNextAsync()).Should().BeTrue(); if (this.TestDatabaseProvider.SupportsCommandExecutionWhileDataReaderIsOpen) { - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeTrue(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeTrue(); } - (await asyncEnumerator.MoveNextAsync()) - .Should().BeTrue(); + (await asyncEnumerator.MoveNextAsync()).Should().BeTrue(); - (await asyncEnumerator.MoveNextAsync()) - .Should().BeFalse(); + (await asyncEnumerator.MoveNextAsync()).Should().BeFalse(); await asyncEnumerator.DisposeAsync(); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - Query_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable(bool useAsyncApi) + public async Task Query_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entities = this.CreateEntitiesInDb(5); var entityIds = entities.Take(2).Select(a => a.Id).ToList(); - (await CallApi( - useAsyncApi, - this.Connection, - $""" - SELECT * - FROM {Q("Entity")} - WHERE {Q("Id")} IN (SELECT {Q("Value")} FROM {TemporaryTable(entityIds)}) - """, - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities.Take(2)); + ( + await CallApi( + useAsyncApi, + this.Connection, + $""" + SELECT * + FROM {Q("Entity")} + WHERE {Q("Id")} IN (SELECT {Q("Value")} FROM {TemporaryTable(entityIds)}) + """, + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ).Should().BeEquivalentTo(entities.Take(2)); } [Theory] @@ -921,25 +1049,33 @@ public async Task Query_Transaction_ShouldUseTransaction(bool useAsyncApi) { var entities = this.CreateEntitiesInDb(null, transaction); - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("Entity")}", - transaction, - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities); + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("Entity")}", + transaction, + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities); await transaction.RollbackAsync(); } - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("Entity")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEmpty(); + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("Entity")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEmpty(); } [Theory] @@ -955,110 +1091,121 @@ bool useAsyncApi await Invoking(() => CallApi>( - useAsyncApi, - this.Connection, - $"SELECT '' AS {Q("Value")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + useAsyncApi, + this.Connection, + $"SELECT '' AS {Q("Value")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Value' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Value' returned by the SQL statement contains a value that could not be converted " + + $"to the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } await Invoking(() => CallApi>( - useAsyncApi, - this.Connection, - $"SELECT 'ab' AS {Q("Value")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + useAsyncApi, + this.Connection, + $"SELECT 'ab' AS {Q("Value")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Value' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Value' returned by the SQL statement contains a value that could not be converted " + + $"to the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - Query_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - bool useAsyncApi - ) + public async Task Query_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( + bool useAsyncApi + ) { var character = Generate.Single(); - (await CallApi>( - useAsyncApi, - this.Connection, - $"SELECT '{character}'", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo([ValueTuple.Create(character)]); + ( + await CallApi>( + useAsyncApi, + this.Connection, + $"SELECT '{character}'", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo([ValueTuple.Create(character)]); } [Theory] [InlineData(false)] [InlineData(true)] - public Task Query_ValueTupleType_ColumnDataTypeNotCompatibleWithValueTupleFieldType_ShouldThrow( - bool useAsyncApi - ) => + public Task Query_ValueTupleType_ColumnDataTypeNotCompatibleWithValueTupleFieldType_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi>( - useAsyncApi, - this.Connection, - $"SELECT 123 AS {Q("Value")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + useAsyncApi, + this.Connection, + $"SELECT 123 AS {Q("Value")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The data type System.* of the column 'Value' returned by the SQL statement is not compatible with " + - $"the field type {typeof(TimeSpan)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}.*" + "The data type System.* of the column 'Value' returned by the SQL statement is not compatible with " + + $"the field type {typeof(TimeSpan)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}.*" ); [Theory] [InlineData(false)] [InlineData(true)] - public Task Query_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidInteger_ShouldThrow( - bool useAsyncApi - ) => + public Task Query_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidInteger_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi>( - useAsyncApi, - this.Connection, - $"SELECT 999 AS {Q("Value")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + useAsyncApi, + this.Connection, + $"SELECT 999 AS {Q("Value")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Value' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Value' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - "Could not convert the value '999*' (System.*) to an enum member of the type " + - $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" + "Could not convert the value '999*' (System.*) to an enum member of the type " + + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); [Theory] @@ -1067,22 +1214,25 @@ bool useAsyncApi public Task Query_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidString_ShouldThrow(bool useAsyncApi) => Invoking(() => CallApi>( - useAsyncApi, - this.Connection, - $"SELECT 'NonExistent' AS {Q("Value")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + useAsyncApi, + this.Connection, + $"SELECT 'NonExistent' AS {Q("Value")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Value' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Value' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + - "That string does not match any of the names of the enum's members.*" + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + + "That string does not match any of the names of the enum's members.*" ); [Theory] @@ -1092,13 +1242,17 @@ public async Task Query_ValueTupleType_EnumValueTupleField_ShouldConvertIntegerT { var enumValue = Generate.Single(); - (await CallApi>( - useAsyncApi, - this.Connection, - $"SELECT {(int)enumValue}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo([ValueTuple.Create(enumValue)]); + ( + await CallApi>( + useAsyncApi, + this.Connection, + $"SELECT {(int)enumValue}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo([ValueTuple.Create(enumValue)]); } [Theory] @@ -1108,13 +1262,17 @@ public async Task Query_ValueTupleType_EnumValueTupleField_ShouldConvertStringTo { var enumValue = Generate.Single(); - (await CallApi>( - useAsyncApi, - this.Connection, - $"SELECT '{enumValue}'", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo([ValueTuple.Create(enumValue)]); + ( + await CallApi>( + useAsyncApi, + this.Connection, + $"SELECT '{enumValue}'", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo([ValueTuple.Create(enumValue)]); } [Theory] @@ -1122,43 +1280,46 @@ public async Task Query_ValueTupleType_EnumValueTupleField_ShouldConvertStringTo [InlineData(true)] public Task Query_ValueTupleType_NonNullableValueTupleField_ColumnContainsNull_ShouldThrow(bool useAsyncApi) { - this.Connection.ExecuteNonQuery( - $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)" - ); + this.Connection.ExecuteNonQuery($"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)"); return Invoking(() => CallApi>( - useAsyncApi, - this.Connection, - $"SELECT {Q("BooleanValue")} FROM {Q("Entity")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + useAsyncApi, + this.Connection, + $"SELECT {Q("BooleanValue")} FROM {Q("Entity")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + - $"corresponding field of the value tuple type {typeof(ValueTuple)} is non-nullable.*" + "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + + $"corresponding field of the value tuple type {typeof(ValueTuple)} is non-nullable.*" ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task Query_ValueTupleType_NullableValueTupleField_ColumnContainsNull_ShouldReturnNull( - bool useAsyncApi - ) + public async Task Query_ValueTupleType_NullableValueTupleField_ColumnContainsNull_ShouldReturnNull(bool useAsyncApi) { await this.Connection.ExecuteNonQueryAsync( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("NullableBooleanValue")}) VALUES(1, NULL)" ); - (await CallApi>( - useAsyncApi, - this.Connection, - $"SELECT {Q("NullableBooleanValue")} FROM {Q("Entity")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo([new ValueTuple(null)]); + ( + await CallApi>( + useAsyncApi, + this.Connection, + $"SELECT {Q("NullableBooleanValue")} FROM {Q("Entity")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo([new ValueTuple(null)]); } [Theory] @@ -1169,17 +1330,20 @@ bool useAsyncApi ) => Invoking(() => CallApi<(int, int)>( - useAsyncApi, - this.Connection, - "SELECT 1", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + useAsyncApi, + this.Connection, + "SELECT 1", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The SQL statement returned 1 column, but the value tuple type {typeof((int, int))} has 2 " + - "fields. Make sure that the SQL statement returns the same number of columns as the number of " + - "fields in the value tuple type.*" + $"The SQL statement returned 1 column, but the value tuple type {typeof((int, int))} has 2 " + + "fields. Make sure that the SQL statement returns the same number of columns as the number of " + + "fields in the value tuple type.*" ); [Theory] @@ -1189,13 +1353,17 @@ public async Task Query_ValueTupleType_ShouldMaterializeBinaryData(bool useAsync { var bytes = Generate.Single(); - (await CallApi>( - useAsyncApi, - this.Connection, - $"SELECT {Parameter(bytes)} AS BinaryData", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo([ValueTuple.Create(bytes)]); + ( + await CallApi>( + useAsyncApi, + this.Connection, + $"SELECT {Parameter(bytes)} AS BinaryData", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo([ValueTuple.Create(bytes)]); } [Theory] @@ -1207,13 +1375,17 @@ public async Task Query_ValueTupleType_ShouldSupportDateTimeOffsetValues(bool us var entities = this.CreateEntitiesInDb(); - (await CallApi<(long Id, DateTimeOffset DateTimeOffsetValue)>( - useAsyncApi, - this.Connection, - $"SELECT {Q("Id")}, {Q("DateTimeOffsetValue")} FROM {Q("EntityWithDateTimeOffset")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities.Select(e => (e.Id, e.DateTimeOffsetValue))); + ( + await CallApi<(long Id, DateTimeOffset DateTimeOffsetValue)>( + useAsyncApi, + this.Connection, + $"SELECT {Q("Id")}, {Q("DateTimeOffsetValue")} FROM {Q("EntityWithDateTimeOffset")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities.Select(e => (e.Id, e.DateTimeOffsetValue))); } [Theory] @@ -1227,13 +1399,16 @@ public Task Query_ValueTupleType_UnsupportedFieldType_ShouldThrow(bool useAsyncA return Invoking(() => CallApi>( - useAsyncApi, - this.Connection, - $"SELECT {literal} AS {Q("Value")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken).AsTask() + useAsyncApi, + this.Connection, + $"SELECT {literal} AS {Q("Value")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( "The data type System.* of the column 'Value' returned by the SQL statement is not supported.*" ); @@ -1251,21 +1426,11 @@ private static IAsyncEnumerable CallApi( { if (useAsyncApi) { - return connection.QueryAsync( - statement, - transaction, - commandTimeout, - commandType, - cancellationToken - ); + return connection.QueryAsync(statement, transaction, commandTimeout, commandType, cancellationToken); } - return connection.Query( - statement, - transaction, - commandTimeout, - commandType, - cancellationToken - ).ToAsyncEnumerable(); + return connection + .Query(statement, transaction, commandTimeout, commandType, cancellationToken) + .ToAsyncEnumerable(); } } diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOfTTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOfTTests.cs index b6907bf..c000ea3 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOfTTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOfTTests.cs @@ -2,28 +2,23 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests; -public sealed class - DbConnectionExtensions_QuerySingleOfTTests_MySql : - DbConnectionExtensions_QuerySingleOfTTests; +public sealed class DbConnectionExtensions_QuerySingleOfTTests_MySql + : DbConnectionExtensions_QuerySingleOfTTests; -public sealed class - DbConnectionExtensions_QuerySingleOfTTests_Oracle : - DbConnectionExtensions_QuerySingleOfTTests; +public sealed class DbConnectionExtensions_QuerySingleOfTTests_Oracle + : DbConnectionExtensions_QuerySingleOfTTests; -public sealed class - DbConnectionExtensions_QuerySingleOfTTests_PostgreSql : - DbConnectionExtensions_QuerySingleOfTTests; +public sealed class DbConnectionExtensions_QuerySingleOfTTests_PostgreSql + : DbConnectionExtensions_QuerySingleOfTTests; -public sealed class - DbConnectionExtensions_QuerySingleOfTTests_Sqlite : - DbConnectionExtensions_QuerySingleOfTTests; +public sealed class DbConnectionExtensions_QuerySingleOfTTests_Sqlite + : DbConnectionExtensions_QuerySingleOfTTests; -public sealed class - DbConnectionExtensions_QuerySingleOfTTests_SqlServer : - DbConnectionExtensions_QuerySingleOfTTests; +public sealed class DbConnectionExtensions_QuerySingleOfTTests_SqlServer + : DbConnectionExtensions_QuerySingleOfTTests; -public abstract class - DbConnectionExtensions_QuerySingleOfTTests : IntegrationTestsBase +public abstract class DbConnectionExtensions_QuerySingleOfTTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { [Theory] @@ -37,7 +32,8 @@ bool useAsyncApi { // Oracle doesn't allow to return an empty string, because it treats empty strings as NULLs. - (await Invoking(() => + ( + await Invoking(() => CallApi( useAsyncApi, this.Connection, @@ -45,19 +41,22 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value '' ({typeof(string)}), " + - $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" - )) + $"The first column returned by the SQL statement contains the value '' ({typeof(string)}), " + + $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" + ) + ) .WithInnerException() .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly " + - "one character long." + $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly " + + "one character long." ); } - (await Invoking(() => + ( + await Invoking(() => CallApi( useAsyncApi, this.Connection, @@ -65,35 +64,39 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value 'ab' ({typeof(string)}), " + - $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" - )) + $"The first column returned by the SQL statement contains the value 'ab' ({typeof(string)}), " + + $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" + ) + ) .WithInnerException() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + - "one character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + + "one character long." ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingle_BuiltInType_CharTargetType_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - bool useAsyncApi - ) + public async Task QuerySingle_BuiltInType_CharTargetType_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( + bool useAsyncApi + ) { var character = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT '{character}'", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(character); + ) + ) + .Should() + .Be(character); } [Theory] @@ -108,10 +111,11 @@ public Task QuerySingle_BuiltInType_ColumnValueCannotBeConvertedToTargetType_Sho cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value 'A' ({typeof(string)}), which " + - $"could not be converted to the type {typeof(int)}. See inner exception for details.*" + $"The first column returned by the SQL statement contains the value 'A' ({typeof(string)}), which " + + $"could not be converted to the type {typeof(int)}. See inner exception for details.*" ); [Theory] @@ -126,10 +130,11 @@ public Task QuerySingle_BuiltInType_EnumTargetType_ColumnContainsInvalidInteger_ cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column returned by the SQL statement contains the value '999*' (System.*), which " + - $"could not be converted to the type {typeof(TestEnum)}. See inner exception for details.*" + "The first column returned by the SQL statement contains the value '999*' (System.*), which " + + $"could not be converted to the type {typeof(TestEnum)}. See inner exception for details.*" ); [Theory] @@ -144,11 +149,12 @@ public Task QuerySingle_BuiltInType_EnumTargetType_ColumnContainsInvalidString_S cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column returned by the SQL statement contains the value 'NonExistent' " + - $"({typeof(string)}), which could not be converted to the type {typeof(TestEnum)}. See inner " + - "exception for details.*" + "The first column returned by the SQL statement contains the value 'NonExistent' " + + $"({typeof(string)}), which could not be converted to the type {typeof(TestEnum)}. See inner " + + "exception for details.*" ); [Theory] @@ -158,13 +164,16 @@ public async Task QuerySingle_BuiltInType_EnumTargetType_ShouldConvertIntegerToE { var enumValue = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT {(int)enumValue}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(enumValue); + ) + ) + .Should() + .Be(enumValue); } [Theory] @@ -174,13 +183,16 @@ public async Task QuerySingle_BuiltInType_EnumTargetType_ShouldConvertStringToEn { var enumValue = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT '{enumValue.ToString()}'", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(enumValue); + ) + ) + .Should() + .Be(enumValue); } [Theory] @@ -195,10 +207,11 @@ public Task QuerySingle_BuiltInType_NonNullableTargetType_ColumnContainsNull_Sho cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column returned by the SQL statement contains a NULL value, which could not be converted " + - $"to the type {typeof(int)}. See inner exception for details.*" + "The first column returned by the SQL statement contains a NULL value, which could not be converted " + + $"to the type {typeof(int)}. See inner exception for details.*" ); [Theory] @@ -207,13 +220,16 @@ public Task QuerySingle_BuiltInType_NonNullableTargetType_ColumnContainsNull_Sho public async Task QuerySingle_BuiltInType_NullableTargetType_ColumnContainsNull_ShouldReturnNull( bool useAsyncApi ) => - (await CallApi( - useAsyncApi, - this.Connection, - "SELECT NULL", - cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeNull(); + ( + await CallApi( + useAsyncApi, + this.Connection, + "SELECT NULL", + cancellationToken: TestContext.Current.CancellationToken + ) + ) + .Should() + .BeNull(); [Theory] [InlineData(false)] @@ -224,13 +240,16 @@ public async Task QuerySingle_BuiltInType_ShouldSupportDateTimeOffsetValues(bool var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("DateTimeOffsetValue")} FROM {Q("EntityWithDateTimeOffset")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(entity.DateTimeOffsetValue); + ) + ) + .Should() + .Be(entity.DateTimeOffsetValue); } [Theory] @@ -252,7 +271,8 @@ await Invoking(() => cancellationToken: cancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); } @@ -265,21 +285,23 @@ public async Task QuerySingle_CommandType_ShouldUseCommandType(bool useAsyncApi) var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, "GetFirstEntity", commandType: CommandType.StoredProcedure, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingle_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) + public async Task QuerySingle_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -289,44 +311,49 @@ public async Task var temporaryTableName = statement.TemporaryTables[0].Name; - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, statement, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingle_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - bool useAsyncApi - ) + public async Task QuerySingle_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entity = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {TemporaryTable([entity])}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingle_EntityType_CharEntityProperty_ColumnContainsStringWithLengthNotOne_ShouldThrow(bool useAsyncApi) + public async Task QuerySingle_EntityType_CharEntityProperty_ColumnContainsStringWithLengthNotOne_ShouldThrow( + bool useAsyncApi + ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) { @@ -340,16 +367,17 @@ await Invoking(() => cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'CharValue' returned by the SQL statement contains a value that could not be " + - $"converted to the type {typeof(char)} of the corresponding property of the type " + - $"{typeof(Entity)}. See inner exception for details.*" + "The column 'CharValue' returned by the SQL statement contains a value that could not be " + + $"converted to the type {typeof(char)} of the corresponding property of the type " + + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } @@ -361,36 +389,39 @@ await Invoking(() => cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(char)} of the corresponding property of the type " + - $"{typeof(Entity)}. See inner exception for details.*" + "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + + $"to the type {typeof(char)} of the corresponding property of the type " + + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingle_EntityType_CharEntityProperty_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - bool useAsyncApi - ) + public async Task QuerySingle_EntityType_CharEntityProperty_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( + bool useAsyncApi + ) { var character = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT '{character}' AS {Q("CharValue")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(new Entity { CharValue = character }); + ) + ) + .Should() + .BeEquivalentTo(new Entity { CharValue = character }); } [Theory] @@ -407,11 +438,12 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The data type System.* of the column 'TimeSpanValue' returned by the SQL statement is not " + - $"compatible with the property type {typeof(TimeSpan)} of the corresponding property of the type " + - $"{typeof(Entity)}.*" + "The data type System.* of the column 'TimeSpanValue' returned by the SQL statement is not " + + $"compatible with the property type {typeof(TimeSpan)} of the corresponding property of the type " + + $"{typeof(Entity)}.*" ); [Theory] @@ -421,14 +453,11 @@ public async Task QuerySingle_EntityType_ColumnHasNoName_ShouldThrow(bool useAsy { InterpolatedSqlStatement statement = this.TestDatabaseProvider switch { - SqlServerTestDatabaseProvider => - "SELECT 1", + SqlServerTestDatabaseProvider => "SELECT 1", - PostgreSqlTestDatabaseProvider or OracleTestDatabaseProvider => - "SELECT 1 AS \" \"", + PostgreSqlTestDatabaseProvider or OracleTestDatabaseProvider => "SELECT 1 AS \" \"", - _ => - "SELECT 1 AS ''" + _ => "SELECT 1 AS ''", }; await Invoking(() => @@ -439,29 +468,31 @@ await Invoking(() => cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The 1st column returned by the SQL statement does not have a name. Make sure that all columns the " + - "statement returns have a name.*" + "The 1st column returned by the SQL statement does not have a name. Make sure that all columns the " + + "statement returns have a name.*" ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_EntityType_CompatiblePrivateConstructor_ShouldUsePrivateConstructor( - bool useAsyncApi - ) + public async Task QuerySingle_EntityType_CompatiblePrivateConstructor_ShouldUsePrivateConstructor(bool useAsyncApi) { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] @@ -471,13 +502,16 @@ public async Task QuerySingle_EntityType_CompatiblePublicConstructor_ShouldUsePu { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] @@ -487,38 +521,42 @@ public async Task QuerySingle_EntityType_EntityTypeHasNoCorrespondingPropertyFor bool useAsyncApi ) { - var entity = (await Invoking(() => - CallApi( - useAsyncApi, - this.Connection, - $"SELECT 1 AS {Q("Id")}, 2 AS {Q("Int32Value")}, 3 AS {Q("NonExistent")}", - cancellationToken: TestContext.Current.CancellationToken + var entity = ( + await Invoking(() => + CallApi( + useAsyncApi, + this.Connection, + $"SELECT 1 AS {Q("Id")}, 2 AS {Q("Int32Value")}, 3 AS {Q("NonExistent")}", + cancellationToken: TestContext.Current.CancellationToken + ) ) - ) - .Should().NotThrowAsync()).Subject; + .Should() + .NotThrowAsync() + ).Subject; - entity - .Should().BeEquivalentTo(new Entity { Id = 1, Int32Value = 2 }); + entity.Should().BeEquivalentTo(new Entity { Id = 1, Int32Value = 2 }); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingle_EntityType_EntityTypeWithPropertiesWithDifferentCasing_ShouldMaterializeEntities( - bool useAsyncApi - ) + public async Task QuerySingle_EntityType_EntityTypeWithPropertiesWithDifferentCasing_ShouldMaterializeEntities( + bool useAsyncApi + ) { var entity = this.CreateEntityInDb(); var entityWithDifferentCasingProperties = Generate.MapTo(entity); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entityWithDifferentCasingProperties); + ) + ) + .Should() + .BeEquivalentTo(entityWithDifferentCasingProperties); } [Theory] @@ -527,23 +565,25 @@ bool useAsyncApi public async Task QuerySingle_EntityType_EnumEntityProperty_ColumnContainsInvalidInteger_ShouldThrow( bool useAsyncApi ) => - await Invoking(() => CallApi( + await Invoking(() => + CallApi( useAsyncApi, this.Connection, $"SELECT 1 AS {Q("Id")}, 999 AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding property of the type " + - $"{typeof(EntityWithEnumStoredAsInteger)}. See inner exception for details.*" + "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding property of the type " + + $"{typeof(EntityWithEnumStoredAsInteger)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - "Could not convert the value '999*' (System.*) to an enum member of the type " + - $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" + "Could not convert the value '999*' (System.*) to an enum member of the type " + + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); [Theory] @@ -552,23 +592,25 @@ await Invoking(() => CallApi( public async Task QuerySingle_EntityType_EnumEntityProperty_ColumnContainsInvalidString_ShouldThrow( bool useAsyncApi ) => - await Invoking(() => CallApi( + await Invoking(() => + CallApi( useAsyncApi, this.Connection, $"SELECT 1 AS {Q("Id")}, 'NonExistent' AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding property of the type " + - $"{typeof(EntityWithEnumStoredAsString)}. See inner exception for details.*" + "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding property of the type " + + $"{typeof(EntityWithEnumStoredAsString)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + - "That string does not match any of the names of the enum's members.*" + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + + "That string does not match any of the names of the enum's members.*" ); [Theory] @@ -578,14 +620,16 @@ public async Task QuerySingle_EntityType_EnumEntityProperty_ShouldConvertInteger { var enumValue = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT 1 AS {Q("Id")}, {(int)enumValue} AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Enum - .Should().Be(enumValue); + ) + ) + .Enum.Should() + .Be(enumValue); } [Theory] @@ -595,14 +639,16 @@ public async Task QuerySingle_EntityType_EnumEntityProperty_ShouldConvertStringT { var enumValue = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT 1 AS {Q("Id")}, '{enumValue.ToString()}' AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Enum - .Should().Be(enumValue); + ) + ) + .Enum.Should() + .Be(enumValue); } [Theory] @@ -612,16 +658,21 @@ public async Task QuerySingle_EntityType_Mapping_Attributes_ShouldUseAttributesM { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("MappingTestEntity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo( + ) + ) + .Should() + .BeEquivalentTo( entity, - options => options.Using(context => context.Subject.Should().BeNull()) - .When(info => info.Path.EndsWith("NotMapped")) + options => + options + .Using(context => context.Subject.Should().BeNull()) + .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -634,16 +685,21 @@ public async Task QuerySingle_EntityType_Mapping_FluentApi_ShouldUseFluentApiMap var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("MappingTestEntity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo( + ) + ) + .Should() + .BeEquivalentTo( entity, - options => options.Using(context => context.Subject.Should().BeNull()) - .When(info => info.Path.EndsWith("NotMapped")) + options => + options + .Using(context => context.Subject.Should().BeNull()) + .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -656,51 +712,56 @@ bool useAsyncApi Invoking(() => CallApi(useAsyncApi, this.Connection, $"SELECT 1 AS {Q("NonExistent")}") ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"Could not materialize an instance of the type {typeof(EntityWithPublicConstructor)}. The type " + - "either needs to have a parameterless constructor or a constructor whose parameters match the " + - "columns returned by the SQL statement, e.g. a constructor that has the following " + - $"signature:{Environment.NewLine}" + - "(* NonExistent).*" + $"Could not materialize an instance of the type {typeof(EntityWithPublicConstructor)}. The type " + + "either needs to have a parameterless constructor or a constructor whose parameters match the " + + "columns returned by the SQL statement, e.g. a constructor that has the following " + + $"signature:{Environment.NewLine}" + + "(* NonExistent).*" ); [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingle_EntityType_NoCompatibleConstructor_PrivateParameterlessConstructor_ShouldUsePrivateConstructorAndProperties( - bool useAsyncApi - ) + public async Task QuerySingle_EntityType_NoCompatibleConstructor_PrivateParameterlessConstructor_ShouldUsePrivateConstructorAndProperties( + bool useAsyncApi + ) { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingle_EntityType_NoCompatibleConstructor_PublicParameterlessConstructor_ShouldUsePublicConstructorAndProperties( - bool useAsyncApi - ) + public async Task QuerySingle_EntityType_NoCompatibleConstructor_PublicParameterlessConstructor_ShouldUsePublicConstructorAndProperties( + bool useAsyncApi + ) { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] @@ -710,13 +771,16 @@ public async Task QuerySingle_EntityType_NoMapping_ShouldUseEntityTypeNameAndPro { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("MappingTestEntity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] @@ -724,9 +788,7 @@ public async Task QuerySingle_EntityType_NoMapping_ShouldUseEntityTypeNameAndPro [InlineData(true)] public Task QuerySingle_EntityType_NonNullableEntityProperty_ColumnContainsNull_ShouldThrow(bool useAsyncApi) { - this.Connection.ExecuteNonQuery( - $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)" - ); + this.Connection.ExecuteNonQuery($"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)"); return Invoking(() => CallApi( @@ -736,10 +798,11 @@ public Task QuerySingle_EntityType_NonNullableEntityProperty_ColumnContainsNull_ cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + - $"corresponding property of the type {typeof(Entity)} is non-nullable.*" + "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + + $"corresponding property of the type {typeof(Entity)} is non-nullable.*" ); } @@ -754,13 +817,16 @@ await this.Connection.ExecuteNonQueryAsync( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("NullableBooleanValue")}) VALUES(1, NULL)" ); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("Id")}, {Q("NullableBooleanValue")} FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(new Entity { Id = 1, NullableBooleanValue = null }); + ) + ) + .Should() + .BeEquivalentTo(new Entity { Id = 1, NullableBooleanValue = null }); } [Theory] @@ -772,13 +838,16 @@ public async Task QuerySingle_EntityType_ShouldSupportDateTimeOffsetValues(bool var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("EntityWithDateTimeOffset")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] @@ -798,7 +867,8 @@ public Task QuerySingle_EntityType_UnsupportedFieldType_ShouldThrow(bool useAsyn cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( "The data type System.* of the column 'Value' returned by the SQL statement is not supported.*" ); @@ -811,13 +881,16 @@ public async Task QuerySingle_InterpolatedParameter_ShouldPassInterpolatedParame { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")} WHERE {Q("Id")} = {Parameter(entity.Id)}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] @@ -832,13 +905,16 @@ public async Task QuerySingle_Parameter_ShouldPassParameter(bool useAsyncApi) ("Id", entity.Id) ); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, statement, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] @@ -848,86 +924,86 @@ public async Task QuerySingle_QueryReturnedMoreThanOneRow_ShouldThrow(bool useAs { this.CreateEntitiesInDb(2); - await Invoking(() => CallApi( + await Invoking(() => + CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() - .WithMessage( - "The SQL statement did return more than one row." - ); + .Should() + .ThrowAsync() + .WithMessage("The SQL statement did return more than one row."); } [Theory] [InlineData(false)] [InlineData(true)] public Task QuerySingle_QueryReturnedNoRows_ShouldThrow(bool useAsyncApi) => - Invoking(() => CallApi( + Invoking(() => + CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")} WHERE {Q("Id")} = -1", cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() - .WithMessage( - "The SQL statement did not return any rows." - ); + .Should() + .ThrowAsync() + .WithMessage("The SQL statement did not return any rows."); [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingle_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) + public async Task QuerySingle_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entityId = Generate.Id(); - InterpolatedSqlStatement statement = - $"SELECT {Q("Value")} AS {Q("Id")} FROM {TemporaryTable([entityId])}"; + InterpolatedSqlStatement statement = $"SELECT {Q("Value")} AS {Q("Id")} FROM {TemporaryTable([entityId])}"; var temporaryTableName = statement.TemporaryTables[0].Name; - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, statement, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(entityId); + ) + ) + .Should() + .Be(entityId); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingle_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - bool useAsyncApi - ) + public async Task QuerySingle_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entity = this.CreateEntityInDb(); var entityId = entity.Id; - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $""" - SELECT * - FROM {Q("Entity")} - WHERE {Q("Id")} IN (SELECT {Q("Value")} FROM {TemporaryTable([entityId])}) - """, + SELECT * + FROM {Q("Entity")} + WHERE {Q("Id")} IN (SELECT {Q("Value")} FROM {TemporaryTable([entityId])}) + """, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ).Should().BeEquivalentTo(entity); } [Theory] @@ -939,35 +1015,39 @@ public async Task QuerySingle_Transaction_ShouldUseTransaction(bool useAsyncApi) { var entity = this.CreateEntityInDb(transaction); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", transaction, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); await transaction.RollbackAsync(); } - await Invoking(() => CallApi( + await Invoking(() => + CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync(); + .Should() + .ThrowAsync(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingle_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthNotOne_ShouldThrow( - bool useAsyncApi - ) + public async Task QuerySingle_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthNotOne_ShouldThrow( + bool useAsyncApi + ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) { @@ -981,16 +1061,17 @@ await Invoking(() => cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Value' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Value' returned by the SQL statement contains a value that could not be converted " + + $"to the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } @@ -1002,36 +1083,39 @@ await Invoking(() => cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Value' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Value' returned by the SQL statement contains a value that could not be converted " + + $"to the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingle_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - bool useAsyncApi - ) + public async Task QuerySingle_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( + bool useAsyncApi + ) { var character = Generate.Single(); - (await CallApi>( + ( + await CallApi>( useAsyncApi, this.Connection, $"SELECT '{character}'", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(ValueTuple.Create(character)); + ) + ) + .Should() + .Be(ValueTuple.Create(character)); } [Theory] @@ -1048,11 +1132,12 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The data type System.* of the column 'Value' returned by the SQL statement is not compatible with " + - $"the field type {typeof(TimeSpan)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}.*" + "The data type System.* of the column 'Value' returned by the SQL statement is not compatible with " + + $"the field type {typeof(TimeSpan)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}.*" ); [Theory] @@ -1069,16 +1154,17 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Value' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Value' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - "Could not convert the value '999*' (System.*) to an enum member of the type " + - $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" + "Could not convert the value '999*' (System.*) to an enum member of the type " + + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); [Theory] @@ -1095,16 +1181,17 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Value' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Value' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + - "That string does not match any of the names of the enum's members.*" + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + + "That string does not match any of the names of the enum's members.*" ); [Theory] @@ -1114,13 +1201,16 @@ public async Task QuerySingle_ValueTupleType_EnumValueTupleField_ShouldConvertIn { var enumValue = Generate.Single(); - (await CallApi>( + ( + await CallApi>( useAsyncApi, this.Connection, $"SELECT {(int)enumValue}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(ValueTuple.Create(enumValue)); + ) + ) + .Should() + .Be(ValueTuple.Create(enumValue)); } [Theory] @@ -1130,25 +1220,24 @@ public async Task QuerySingle_ValueTupleType_EnumValueTupleField_ShouldConvertSt { var enumValue = Generate.Single(); - (await CallApi>( + ( + await CallApi>( useAsyncApi, this.Connection, $"SELECT '{enumValue}'", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(ValueTuple.Create(enumValue)); + ) + ) + .Should() + .Be(ValueTuple.Create(enumValue)); } [Theory] [InlineData(false)] [InlineData(true)] - public Task QuerySingle_ValueTupleType_NonNullableValueTupleField_ColumnContainsNull_ShouldThrow( - bool useAsyncApi - ) + public Task QuerySingle_ValueTupleType_NonNullableValueTupleField_ColumnContainsNull_ShouldThrow(bool useAsyncApi) { - this.Connection.ExecuteNonQuery( - $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)" - ); + this.Connection.ExecuteNonQuery($"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)"); return Invoking(() => CallApi>( @@ -1158,10 +1247,11 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + - $"corresponding field of the value tuple type {typeof(ValueTuple)} is non-nullable.*" + "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + + $"corresponding field of the value tuple type {typeof(ValueTuple)} is non-nullable.*" ); } @@ -1176,13 +1266,16 @@ await this.Connection.ExecuteNonQueryAsync( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("NullableBooleanValue")}) VALUES(1, NULL)" ); - (await CallApi>( + ( + await CallApi>( useAsyncApi, this.Connection, $"SELECT {Q("NullableBooleanValue")} FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(new(null)); + ) + ) + .Should() + .Be(new(null)); } [Theory] @@ -1199,11 +1292,12 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The SQL statement returned 1 column, but the value tuple type {typeof((int, int))} has 2 " + - "fields. Make sure that the SQL statement returns the same number of columns as the number of " + - "fields in the value tuple type.*" + $"The SQL statement returned 1 column, but the value tuple type {typeof((int, int))} has 2 " + + "fields. Make sure that the SQL statement returns the same number of columns as the number of " + + "fields in the value tuple type.*" ); [Theory] @@ -1213,13 +1307,16 @@ public async Task QuerySingle_ValueTupleType_ShouldMaterializeBinaryData(bool us { var bytes = Generate.Single(); - (await CallApi>( + ( + await CallApi>( useAsyncApi, this.Connection, $"SELECT {Parameter(bytes)} AS BinaryData", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(ValueTuple.Create(bytes)); + ) + ) + .Should() + .BeEquivalentTo(ValueTuple.Create(bytes)); } [Theory] @@ -1231,13 +1328,16 @@ public async Task QuerySingle_ValueTupleType_ShouldSupportDateTimeOffsetValues(b var entity = this.CreateEntityInDb(); - (await CallApi<(long Id, DateTimeOffset DateTimeOffsetValue)>( + ( + await CallApi<(long Id, DateTimeOffset DateTimeOffsetValue)>( useAsyncApi, this.Connection, $"SELECT {Q("Id")}, {Q("DateTimeOffsetValue")} FROM {Q("EntityWithDateTimeOffset")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo((entity.Id, entity.DateTimeOffsetValue)); + ) + ) + .Should() + .BeEquivalentTo((entity.Id, entity.DateTimeOffsetValue)); } [Theory] @@ -1257,7 +1357,8 @@ public Task QuerySingle_ValueTupleType_UnsupportedFieldType_ShouldThrow(bool use cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( "The data type System.* of the column 'Value' returned by the SQL statement is not supported.*" ); @@ -1287,13 +1388,7 @@ private static Task CallApi( try { return Task.FromResult( - connection.QuerySingle( - statement, - transaction, - commandTimeout, - commandType, - cancellationToken - ) + connection.QuerySingle(statement, transaction, commandTimeout, commandType, cancellationToken) ); } catch (Exception ex) diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOrDefaultOfTTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOrDefaultOfTTests.cs index 2264ded..00ccb5f 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOrDefaultOfTTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOrDefaultOfTTests.cs @@ -2,44 +2,38 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests; -public sealed class - DbConnectionExtensions_QuerySingleOrDefaultOfTTests_MySql : - DbConnectionExtensions_QuerySingleOrDefaultOfTTests; +public sealed class DbConnectionExtensions_QuerySingleOrDefaultOfTTests_MySql + : DbConnectionExtensions_QuerySingleOrDefaultOfTTests; -public sealed class - DbConnectionExtensions_QuerySingleOrDefaultOfTTests_Oracle : - DbConnectionExtensions_QuerySingleOrDefaultOfTTests; +public sealed class DbConnectionExtensions_QuerySingleOrDefaultOfTTests_Oracle + : DbConnectionExtensions_QuerySingleOrDefaultOfTTests; -public sealed class - DbConnectionExtensions_QuerySingleOrDefaultOfTTests_PostgreSql : - DbConnectionExtensions_QuerySingleOrDefaultOfTTests; +public sealed class DbConnectionExtensions_QuerySingleOrDefaultOfTTests_PostgreSql + : DbConnectionExtensions_QuerySingleOrDefaultOfTTests; -public sealed class - DbConnectionExtensions_QuerySingleOrDefaultOfTTests_Sqlite : - DbConnectionExtensions_QuerySingleOrDefaultOfTTests; +public sealed class DbConnectionExtensions_QuerySingleOrDefaultOfTTests_Sqlite + : DbConnectionExtensions_QuerySingleOrDefaultOfTTests; -public sealed class - DbConnectionExtensions_QuerySingleOrDefaultOfTTests_SqlServer : - DbConnectionExtensions_QuerySingleOrDefaultOfTTests; +public sealed class DbConnectionExtensions_QuerySingleOrDefaultOfTTests_SqlServer + : DbConnectionExtensions_QuerySingleOrDefaultOfTTests; -public abstract class - DbConnectionExtensions_QuerySingleOrDefaultOfTTests : IntegrationTestsBase< - TTestDatabaseProvider> +public abstract class DbConnectionExtensions_QuerySingleOrDefaultOfTTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingleOrDefault_BuiltInType_CharTargetType_ColumnContainsStringWithLengthNotOne_ShouldThrow( - bool useAsyncApi - ) + public async Task QuerySingleOrDefault_BuiltInType_CharTargetType_ColumnContainsStringWithLengthNotOne_ShouldThrow( + bool useAsyncApi + ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) { // Oracle doesn't allow to return an empty string, because it treats empty strings as NULLs. - (await Invoking(() => + ( + await Invoking(() => CallApi( useAsyncApi, this.Connection, @@ -47,19 +41,22 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value '' ({typeof(string)}), " + - $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" - )) + $"The first column returned by the SQL statement contains the value '' ({typeof(string)}), " + + $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" + ) + ) .WithInnerException() .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly " + - "one character long." + $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly " + + "one character long." ); } - (await Invoking(() => + ( + await Invoking(() => CallApi( useAsyncApi, this.Connection, @@ -67,35 +64,39 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value 'ab' ({typeof(string)}), " + - $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" - )) + $"The first column returned by the SQL statement contains the value 'ab' ({typeof(string)}), " + + $"which could not be converted to the type {typeof(char)}. See inner exception for details.*" + ) + ) .WithInnerException() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + - "one character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + + "one character long." ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingleOrDefault_BuiltInType_CharTargetType_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - bool useAsyncApi - ) + public async Task QuerySingleOrDefault_BuiltInType_CharTargetType_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( + bool useAsyncApi + ) { var character = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT '{character}'", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(character); + ) + ) + .Should() + .Be(character); } [Theory] @@ -112,10 +113,11 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The first column returned by the SQL statement contains the value 'A' ({typeof(string)}), which " + - $"could not be converted to the type {typeof(int)}. See inner exception for details.*" + $"The first column returned by the SQL statement contains the value 'A' ({typeof(string)}), which " + + $"could not be converted to the type {typeof(int)}. See inner exception for details.*" ); [Theory] @@ -132,10 +134,11 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column returned by the SQL statement contains the value '999*' (System.*), which " + - $"could not be converted to the type {typeof(TestEnum)}. See inner exception for details.*" + "The first column returned by the SQL statement contains the value '999*' (System.*), which " + + $"could not be converted to the type {typeof(TestEnum)}. See inner exception for details.*" ); [Theory] @@ -152,11 +155,12 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column returned by the SQL statement contains the value 'NonExistent' " + - $"({typeof(string)}), which could not be converted to the type {typeof(TestEnum)}. See inner " + - "exception for details.*" + "The first column returned by the SQL statement contains the value 'NonExistent' " + + $"({typeof(string)}), which could not be converted to the type {typeof(TestEnum)}. See inner " + + "exception for details.*" ); [Theory] @@ -166,13 +170,16 @@ public async Task QuerySingleOrDefault_BuiltInType_EnumTargetType_ShouldConvertI { var enumValue = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT {(int)enumValue}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(enumValue); + ) + ) + .Should() + .Be(enumValue); } [Theory] @@ -182,13 +189,16 @@ public async Task QuerySingleOrDefault_BuiltInType_EnumTargetType_ShouldConvertS { var enumValue = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT '{enumValue.ToString()}'", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(enumValue); + ) + ) + .Should() + .Be(enumValue); } [Theory] @@ -205,10 +215,11 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The first column returned by the SQL statement contains a NULL value, which could not be converted " + - $"to the type {typeof(int)}. See inner exception for details.*" + "The first column returned by the SQL statement contains a NULL value, which could not be converted " + + $"to the type {typeof(int)}. See inner exception for details.*" ); [Theory] @@ -217,13 +228,16 @@ bool useAsyncApi public async Task QuerySingleOrDefault_BuiltInType_NullableTargetType_ColumnContainsNull_ShouldReturnNull( bool useAsyncApi ) => - (await CallApi( - useAsyncApi, - this.Connection, - "SELECT NULL", - cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeNull(); + ( + await CallApi( + useAsyncApi, + this.Connection, + "SELECT NULL", + cancellationToken: TestContext.Current.CancellationToken + ) + ) + .Should() + .BeNull(); [Theory] [InlineData(false)] @@ -234,13 +248,16 @@ public async Task QuerySingleOrDefault_BuiltInType_ShouldSupportDateTimeOffsetVa var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("DateTimeOffsetValue")} FROM {Q("EntityWithDateTimeOffset")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(entity.DateTimeOffsetValue); + ) + ) + .Should() + .Be(entity.DateTimeOffsetValue); } [Theory] @@ -264,7 +281,8 @@ await Invoking(() => cancellationToken: cancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); } @@ -277,21 +295,25 @@ public async Task QuerySingleOrDefault_CommandType_ShouldUseCommandType(bool use var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, "GetFirstEntity", commandType: CommandType.StoredProcedure, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingleOrDefault_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) + public async Task QuerySingleOrDefault_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -301,46 +323,49 @@ public async Task var temporaryTableName = statement.TemporaryTables[0].Name; - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, statement, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingleOrDefault_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - bool useAsyncApi - ) + public async Task QuerySingleOrDefault_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entity = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {TemporaryTable([entity])}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingleOrDefault_EntityType_CharEntityProperty_ColumnContainsStringWithLengthNotOne_ShouldThrow( - bool useAsyncApi - ) + public async Task QuerySingleOrDefault_EntityType_CharEntityProperty_ColumnContainsStringWithLengthNotOne_ShouldThrow( + bool useAsyncApi + ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) { @@ -354,16 +379,17 @@ await Invoking(() => cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'CharValue' returned by the SQL statement contains a value that could not be " + - $"converted to the type {typeof(char)} of the corresponding property of the type " + - $"{typeof(Entity)}. See inner exception for details.*" + "The column 'CharValue' returned by the SQL statement contains a value that could not be " + + $"converted to the type {typeof(char)} of the corresponding property of the type " + + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } @@ -375,36 +401,39 @@ await Invoking(() => cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(char)} of the corresponding property of the type " + - $"{typeof(Entity)}. See inner exception for details.*" + "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + + $"to the type {typeof(char)} of the corresponding property of the type " + + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingleOrDefault_EntityType_CharEntityProperty_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - bool useAsyncApi - ) + public async Task QuerySingleOrDefault_EntityType_CharEntityProperty_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( + bool useAsyncApi + ) { var character = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT '{character}' AS {Q("CharValue")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(new Entity { CharValue = character }); + ) + ) + .Should() + .BeEquivalentTo(new Entity { CharValue = character }); } [Theory] @@ -421,11 +450,12 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The data type System.* of the column 'TimeSpanValue' returned by the SQL statement is not " + - $"compatible with the property type {typeof(TimeSpan)} of the corresponding property of the type " + - $"{typeof(Entity)}.*" + "The data type System.* of the column 'TimeSpanValue' returned by the SQL statement is not " + + $"compatible with the property type {typeof(TimeSpan)} of the corresponding property of the type " + + $"{typeof(Entity)}.*" ); [Theory] @@ -435,14 +465,11 @@ public async Task QuerySingleOrDefault_EntityType_ColumnHasNoName_ShouldThrow(bo { InterpolatedSqlStatement statement = this.TestDatabaseProvider switch { - SqlServerTestDatabaseProvider => - "SELECT 1", + SqlServerTestDatabaseProvider => "SELECT 1", - PostgreSqlTestDatabaseProvider or OracleTestDatabaseProvider => - "SELECT 1 AS \" \"", + PostgreSqlTestDatabaseProvider or OracleTestDatabaseProvider => "SELECT 1 AS \" \"", - _ => - "SELECT 1 AS ''" + _ => "SELECT 1 AS ''", }; await Invoking(() => @@ -453,10 +480,11 @@ await Invoking(() => cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The 1st column returned by the SQL statement does not have a name. Make sure that all columns the " + - "statement returns have a name.*" + "The 1st column returned by the SQL statement does not have a name. Make sure that all columns the " + + "statement returns have a name.*" ); } @@ -469,13 +497,16 @@ bool useAsyncApi { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] @@ -487,107 +518,115 @@ bool useAsyncApi { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingleOrDefault_EntityType_EntityTypeHasNoCorrespondingPropertyForColumn_ShouldIgnoreColumn( - bool useAsyncApi - ) + public async Task QuerySingleOrDefault_EntityType_EntityTypeHasNoCorrespondingPropertyForColumn_ShouldIgnoreColumn( + bool useAsyncApi + ) { - var entity = (await Invoking(() => - CallApi( - useAsyncApi, - this.Connection, - $"SELECT 1 AS {Q("Id")}, 2 AS {Q("Int32Value")}, 3 AS {Q("NonExistent")}", - cancellationToken: TestContext.Current.CancellationToken + var entity = ( + await Invoking(() => + CallApi( + useAsyncApi, + this.Connection, + $"SELECT 1 AS {Q("Id")}, 2 AS {Q("Int32Value")}, 3 AS {Q("NonExistent")}", + cancellationToken: TestContext.Current.CancellationToken + ) ) - ) - .Should().NotThrowAsync()).Subject; + .Should() + .NotThrowAsync() + ).Subject; - entity - .Should().BeEquivalentTo(new Entity { Id = 1, Int32Value = 2 }); + entity.Should().BeEquivalentTo(new Entity { Id = 1, Int32Value = 2 }); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingleOrDefault_EntityType_EntityTypeWithPropertiesWithDifferentCasing_ShouldMaterializeEntities( - bool useAsyncApi - ) + public async Task QuerySingleOrDefault_EntityType_EntityTypeWithPropertiesWithDifferentCasing_ShouldMaterializeEntities( + bool useAsyncApi + ) { var entity = this.CreateEntityInDb(); var entityWithDifferentCasingProperties = Generate.MapTo(entity); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entityWithDifferentCasingProperties); + ) + ) + .Should() + .BeEquivalentTo(entityWithDifferentCasingProperties); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingleOrDefault_EntityType_EnumEntityProperty_ColumnContainsInvalidInteger_ShouldThrow( - bool useAsyncApi - ) => - await Invoking(() => CallApi( + public async Task QuerySingleOrDefault_EntityType_EnumEntityProperty_ColumnContainsInvalidInteger_ShouldThrow( + bool useAsyncApi + ) => + await Invoking(() => + CallApi( useAsyncApi, this.Connection, $"SELECT 1 AS {Q("Id")}, 999 AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding property of the type " + - $"{typeof(EntityWithEnumStoredAsInteger)}. See inner exception for details.*" + "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding property of the type " + + $"{typeof(EntityWithEnumStoredAsInteger)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - "Could not convert the value '999*' (System.*) to an enum member of the type " + - $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" + "Could not convert the value '999*' (System.*) to an enum member of the type " + + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingleOrDefault_EntityType_EnumEntityProperty_ColumnContainsInvalidString_ShouldThrow( - bool useAsyncApi - ) => - await Invoking(() => CallApi( + public async Task QuerySingleOrDefault_EntityType_EnumEntityProperty_ColumnContainsInvalidString_ShouldThrow( + bool useAsyncApi + ) => + await Invoking(() => + CallApi( useAsyncApi, this.Connection, $"SELECT 1 AS {Q("Id")}, 'NonExistent' AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding property of the type " + - $"{typeof(EntityWithEnumStoredAsString)}. See inner exception for details.*" + "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding property of the type " + + $"{typeof(EntityWithEnumStoredAsString)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + - "That string does not match any of the names of the enum's members.*" + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + + "That string does not match any of the names of the enum's members.*" ); [Theory] @@ -597,14 +636,16 @@ public async Task QuerySingleOrDefault_EntityType_EnumEntityProperty_ShouldConve { var enumValue = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT 1 AS {Q("Id")}, {(int)enumValue} AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken - ))! - .Enum - .Should().Be(enumValue); + ) + )! + .Enum.Should() + .Be(enumValue); } [Theory] @@ -614,14 +655,16 @@ public async Task QuerySingleOrDefault_EntityType_EnumEntityProperty_ShouldConve { var enumValue = Generate.Single(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT 1 AS {Q("Id")}, '{enumValue.ToString()}' AS {Q("Enum")}", cancellationToken: TestContext.Current.CancellationToken - ))! - .Enum - .Should().Be(enumValue); + ) + )! + .Enum.Should() + .Be(enumValue); } [Theory] @@ -631,16 +674,21 @@ public async Task QuerySingleOrDefault_EntityType_Mapping_Attributes_ShouldUseAt { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("MappingTestEntity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo( + ) + ) + .Should() + .BeEquivalentTo( entity, - options => options.Using(context => context.Subject.Should().BeNull()) - .When(info => info.Path.EndsWith("NotMapped")) + options => + options + .Using(context => context.Subject.Should().BeNull()) + .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -653,16 +701,21 @@ public async Task QuerySingleOrDefault_EntityType_Mapping_FluentApi_ShouldUseFlu var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("MappingTestEntity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo( + ) + ) + .Should() + .BeEquivalentTo( entity, - options => options.Using(context => context.Subject.Should().BeNull()) - .When(info => info.Path.EndsWith("NotMapped")) + options => + options + .Using(context => context.Subject.Should().BeNull()) + .When(info => info.Path.EndsWith("NotMapped")) ); } @@ -673,57 +726,58 @@ public Task QuerySingleOrDefault_EntityType_NoCompatibleConstructor_NoParameterl bool useAsyncApi ) => Invoking(() => - CallApi( - useAsyncApi, - this.Connection, - $"SELECT 1 AS {Q("NonExistent")}" - ) + CallApi(useAsyncApi, this.Connection, $"SELECT 1 AS {Q("NonExistent")}") ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"Could not materialize an instance of the type {typeof(EntityWithPublicConstructor)}. The type " + - "either needs to have a parameterless constructor or a constructor whose parameters match the " + - "columns returned by the SQL statement, e.g. a constructor that has the following " + - $"signature:{Environment.NewLine}" + - "(* NonExistent).*" + $"Could not materialize an instance of the type {typeof(EntityWithPublicConstructor)}. The type " + + "either needs to have a parameterless constructor or a constructor whose parameters match the " + + "columns returned by the SQL statement, e.g. a constructor that has the following " + + $"signature:{Environment.NewLine}" + + "(* NonExistent).*" ); [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingleOrDefault_EntityType_NoCompatibleConstructor_PrivateParameterlessConstructor_ShouldUsePrivateConstructorAndProperties( - bool useAsyncApi - ) + public async Task QuerySingleOrDefault_EntityType_NoCompatibleConstructor_PrivateParameterlessConstructor_ShouldUsePrivateConstructorAndProperties( + bool useAsyncApi + ) { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingleOrDefault_EntityType_NoCompatibleConstructor_PublicParameterlessConstructor_ShouldUsePublicConstructorAndProperties( - bool useAsyncApi - ) + public async Task QuerySingleOrDefault_EntityType_NoCompatibleConstructor_PublicParameterlessConstructor_ShouldUsePublicConstructorAndProperties( + bool useAsyncApi + ) { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] @@ -735,13 +789,16 @@ bool useAsyncApi { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("MappingTestEntity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] @@ -751,9 +808,7 @@ public Task QuerySingleOrDefault_EntityType_NonNullableEntityProperty_ColumnCont bool useAsyncApi ) { - this.Connection.ExecuteNonQuery( - $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)" - ); + this.Connection.ExecuteNonQuery($"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)"); return Invoking(() => CallApi( @@ -763,10 +818,11 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + - $"corresponding property of the type {typeof(Entity)} is non-nullable.*" + "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + + $"corresponding property of the type {typeof(Entity)} is non-nullable.*" ); } @@ -781,13 +837,16 @@ await this.Connection.ExecuteNonQueryAsync( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("NullableBooleanValue")}) VALUES(1, NULL)" ); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("Id")}, {Q("NullableBooleanValue")} FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(new Entity { Id = 1, NullableBooleanValue = null }); + ) + ) + .Should() + .BeEquivalentTo(new Entity { Id = 1, NullableBooleanValue = null }); } [Theory] @@ -799,13 +858,16 @@ public async Task QuerySingleOrDefault_EntityType_ShouldSupportDateTimeOffsetVal var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("EntityWithDateTimeOffset")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] @@ -825,7 +887,8 @@ public Task QuerySingleOrDefault_EntityType_UnsupportedFieldType_ShouldThrow(boo cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( "The data type System.* of the column 'Value' returned by the SQL statement is not supported.*" ); @@ -838,13 +901,16 @@ public async Task QuerySingleOrDefault_InterpolatedParameter_ShouldPassInterpola { var entity = this.CreateEntityInDb(); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")} WHERE {Q("Id")} = {Parameter(entity.Id)}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] @@ -859,13 +925,16 @@ public async Task QuerySingleOrDefault_Parameter_ShouldPassParameter(bool useAsy ("Id", entity.Id) ); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, statement, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); } [Theory] @@ -875,17 +944,17 @@ public async Task QuerySingleOrDefault_QueryReturnedMoreThanOneRow_ShouldThrow(b { this.CreateEntitiesInDb(2); - await Invoking(() => CallApi( + await Invoking(() => + CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() - .WithMessage( - "The SQL statement did return more than one row." - ); + .Should() + .ThrowAsync() + .WithMessage("The SQL statement did return more than one row."); } [Theory] @@ -893,82 +962,93 @@ await Invoking(() => CallApi( [InlineData(true)] public async Task QuerySingleOrDefault_QueryReturnedNoRows_ShouldThrow(bool useAsyncApi) { - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT {Q("Id")} FROM {Q("Entity")} WHERE {Q("Id")} = -1", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(0); + ) + ) + .Should() + .Be(0); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")} WHERE {Q("Id")} = -1", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeNull(); + ) + ) + .Should() + .BeNull(); - (await CallApi<(long, string)>( + ( + await CallApi<(long, string)>( useAsyncApi, this.Connection, $"SELECT {Q("Id")}, {Q("StringValue")} FROM {Q("Entity")} WHERE {Q("Id")} = -1", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(default); + ) + ) + .Should() + .Be(default); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingleOrDefault_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) + public async Task QuerySingleOrDefault_ScalarValuesTemporaryTable_ShouldDropTemporaryTableAfterExecution( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entityId = Generate.Id(); - InterpolatedSqlStatement statement = - $"SELECT {Q("Value")} AS {Q("Id")} FROM {TemporaryTable([entityId])}"; + InterpolatedSqlStatement statement = $"SELECT {Q("Value")} AS {Q("Id")} FROM {TemporaryTable([entityId])}"; var temporaryTableName = statement.TemporaryTables[0].Name; - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, statement, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(entityId); + ) + ) + .Should() + .Be(entityId); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingleOrDefault_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - bool useAsyncApi - ) + public async Task QuerySingleOrDefault_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entity = this.CreateEntityInDb(); var entityId = entity.Id; - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $""" - SELECT * - FROM {Q("Entity")} - WHERE {Q("Id")} IN (SELECT {Q("Value")} FROM {TemporaryTable([entityId])}) - """, + SELECT * + FROM {Q("Entity")} + WHERE {Q("Id")} IN (SELECT {Q("Value")} FROM {TemporaryTable([entityId])}) + """, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ).Should().BeEquivalentTo(entity); } [Theory] @@ -980,34 +1060,39 @@ public async Task QuerySingleOrDefault_Transaction_ShouldUseTransaction(bool use { var entity = this.CreateEntityInDb(transaction); - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", transaction, cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(entity); + ) + ) + .Should() + .BeEquivalentTo(entity); await transaction.RollbackAsync(); } - (await CallApi( + ( + await CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeNull(); + ) + ) + .Should() + .BeNull(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingleOrDefault_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthNotOne_ShouldThrow( - bool useAsyncApi - ) + public async Task QuerySingleOrDefault_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthNotOne_ShouldThrow( + bool useAsyncApi + ) { if (this.TestDatabaseProvider is not OracleTestDatabaseProvider) { @@ -1021,16 +1106,17 @@ await Invoking(() => cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Value' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Value' returned by the SQL statement contains a value that could not be converted " + + $"to the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string '' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } @@ -1042,45 +1128,47 @@ await Invoking(() => cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Value' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Value' returned by the SQL statement contains a value that could not be converted " + + $"to the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + - "exactly one character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be " + + "exactly one character long." ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingleOrDefault_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( - bool useAsyncApi - ) + public async Task QuerySingleOrDefault_ValueTupleType_CharValueTupleField_ColumnContainsStringWithLengthOne_ShouldGetFirstCharacter( + bool useAsyncApi + ) { var character = Generate.Single(); - (await CallApi>( + ( + await CallApi>( useAsyncApi, this.Connection, $"SELECT '{character}'", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(ValueTuple.Create(character)); + ) + ) + .Should() + .Be(ValueTuple.Create(character)); } [Theory] [InlineData(false)] [InlineData(true)] - public Task - QuerySingleOrDefault_ValueTupleType_ColumnDataTypeNotCompatibleWithValueTupleFieldType_ShouldThrow( - bool useAsyncApi - ) => + public Task QuerySingleOrDefault_ValueTupleType_ColumnDataTypeNotCompatibleWithValueTupleFieldType_ShouldThrow( + bool useAsyncApi + ) => Invoking(() => CallApi>( useAsyncApi, @@ -1089,20 +1177,20 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The data type System.* of the column 'Value' returned by the SQL statement is not compatible with " + - $"the field type {typeof(TimeSpan)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}.*" + "The data type System.* of the column 'Value' returned by the SQL statement is not compatible with " + + $"the field type {typeof(TimeSpan)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}.*" ); [Theory] [InlineData(false)] [InlineData(true)] - public Task - QuerySingleOrDefault_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidInteger_ShouldThrow( - bool useAsyncApi - ) => + public Task QuerySingleOrDefault_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidInteger_ShouldThrow( + bool useAsyncApi + ) => Invoking(() => CallApi>( useAsyncApi, @@ -1111,25 +1199,25 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Value' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Value' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - "Could not convert the value '999*' (System.*) to an enum member of the type " + - $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" + "Could not convert the value '999*' (System.*) to an enum member of the type " + + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); [Theory] [InlineData(false)] [InlineData(true)] - public Task - QuerySingleOrDefault_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidString_ShouldThrow( - bool useAsyncApi - ) => + public Task QuerySingleOrDefault_ValueTupleType_EnumValueTupleField_ColumnContainsInvalidString_ShouldThrow( + bool useAsyncApi + ) => Invoking(() => CallApi>( useAsyncApi, @@ -1138,16 +1226,17 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'Value' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Value' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException(typeof(InvalidCastException)) .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + - "That string does not match any of the names of the enum's members.*" + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + + "That string does not match any of the names of the enum's members.*" ); [Theory] @@ -1159,13 +1248,16 @@ bool useAsyncApi { var enumValue = Generate.Single(); - (await CallApi>( + ( + await CallApi>( useAsyncApi, this.Connection, $"SELECT {(int)enumValue}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(ValueTuple.Create(enumValue)); + ) + ) + .Should() + .Be(ValueTuple.Create(enumValue)); } [Theory] @@ -1177,13 +1269,16 @@ bool useAsyncApi { var enumValue = Generate.Single(); - (await CallApi>( + ( + await CallApi>( useAsyncApi, this.Connection, $"SELECT '{enumValue}'", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(ValueTuple.Create(enumValue)); + ) + ) + .Should() + .Be(ValueTuple.Create(enumValue)); } [Theory] @@ -1193,9 +1288,7 @@ public Task QuerySingleOrDefault_ValueTupleType_NonNullableValueTupleField_Colum bool useAsyncApi ) { - this.Connection.ExecuteNonQuery( - $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)" - ); + this.Connection.ExecuteNonQuery($"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("BooleanValue")}) VALUES(1, NULL)"); return Invoking(() => CallApi>( @@ -1205,41 +1298,43 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + - $"corresponding field of the value tuple type {typeof(ValueTuple)} is non-nullable.*" + "The column 'BooleanValue' returned by the SQL statement contains a NULL value, but the " + + $"corresponding field of the value tuple type {typeof(ValueTuple)} is non-nullable.*" ); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingleOrDefault_ValueTupleType_NullableValueTupleField_ColumnContainsNull_ShouldReturnNull( - bool useAsyncApi - ) + public async Task QuerySingleOrDefault_ValueTupleType_NullableValueTupleField_ColumnContainsNull_ShouldReturnNull( + bool useAsyncApi + ) { await this.Connection.ExecuteNonQueryAsync( $"INSERT INTO {Q("Entity")} ({Q("Id")}, {Q("NullableBooleanValue")}) VALUES(1, NULL)" ); - (await CallApi>( + ( + await CallApi>( useAsyncApi, this.Connection, $"SELECT {Q("NullableBooleanValue")} FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().Be(new(null)); + ) + ) + .Should() + .Be(new(null)); } [Theory] [InlineData(false)] [InlineData(true)] - public Task - QuerySingleOrDefault_ValueTupleType_NumberOfColumnsDoesNotMatchNumberOfValueTupleFields_ShouldThrow( - bool useAsyncApi - ) => + public Task QuerySingleOrDefault_ValueTupleType_NumberOfColumnsDoesNotMatchNumberOfValueTupleFields_ShouldThrow( + bool useAsyncApi + ) => Invoking(() => CallApi<(int, int)>( useAsyncApi, @@ -1248,11 +1343,12 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The SQL statement returned 1 column, but the value tuple type {typeof((int, int))} has 2 " + - "fields. Make sure that the SQL statement returns the same number of columns as the number of " + - "fields in the value tuple type.*" + $"The SQL statement returned 1 column, but the value tuple type {typeof((int, int))} has 2 " + + "fields. Make sure that the SQL statement returns the same number of columns as the number of " + + "fields in the value tuple type.*" ); [Theory] @@ -1262,13 +1358,16 @@ public async Task QuerySingleOrDefault_ValueTupleType_ShouldMaterializeBinaryDat { var bytes = Generate.Single(); - (await CallApi>( + ( + await CallApi>( useAsyncApi, this.Connection, $"SELECT {Parameter(bytes)} AS BinaryData", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo(ValueTuple.Create(bytes)); + ) + ) + .Should() + .BeEquivalentTo(ValueTuple.Create(bytes)); } [Theory] @@ -1280,13 +1379,16 @@ public async Task QuerySingleOrDefault_ValueTupleType_ShouldSupportDateTimeOffse var entity = this.CreateEntityInDb(); - (await CallApi<(long Id, DateTimeOffset DateTimeOffsetValue)>( + ( + await CallApi<(long Id, DateTimeOffset DateTimeOffsetValue)>( useAsyncApi, this.Connection, $"SELECT {Q("Id")}, {Q("DateTimeOffsetValue")} FROM {Q("EntityWithDateTimeOffset")}", cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeEquivalentTo((entity.Id, entity.DateTimeOffsetValue)); + ) + ) + .Should() + .BeEquivalentTo((entity.Id, entity.DateTimeOffsetValue)); } [Theory] @@ -1306,7 +1408,8 @@ public Task QuerySingleOrDefault_ValueTupleType_UnsupportedFieldType_ShouldThrow cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( "The data type System.* of the column 'Value' returned by the SQL statement is not supported.*" ); diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOrDefaultTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOrDefaultTests.cs index 92b0e9e..9878280 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOrDefaultTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleOrDefaultTests.cs @@ -4,29 +4,23 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests; -public sealed class - DbConnectionExtensions_QuerySingleOrDefaultTests_MySql : - DbConnectionExtensions_QuerySingleOrDefaultTests; +public sealed class DbConnectionExtensions_QuerySingleOrDefaultTests_MySql + : DbConnectionExtensions_QuerySingleOrDefaultTests; -public sealed class - DbConnectionExtensions_QuerySingleOrDefaultTests_Oracle : - DbConnectionExtensions_QuerySingleOrDefaultTests; +public sealed class DbConnectionExtensions_QuerySingleOrDefaultTests_Oracle + : DbConnectionExtensions_QuerySingleOrDefaultTests; -public sealed class - DbConnectionExtensions_QuerySingleOrDefaultTests_PostgreSql : - DbConnectionExtensions_QuerySingleOrDefaultTests; +public sealed class DbConnectionExtensions_QuerySingleOrDefaultTests_PostgreSql + : DbConnectionExtensions_QuerySingleOrDefaultTests; -public sealed class - DbConnectionExtensions_QuerySingleOrDefaultTests_Sqlite : - DbConnectionExtensions_QuerySingleOrDefaultTests; +public sealed class DbConnectionExtensions_QuerySingleOrDefaultTests_Sqlite + : DbConnectionExtensions_QuerySingleOrDefaultTests; -public sealed class - DbConnectionExtensions_QuerySingleOrDefaultTests_SqlServer : - DbConnectionExtensions_QuerySingleOrDefaultTests; +public sealed class DbConnectionExtensions_QuerySingleOrDefaultTests_SqlServer + : DbConnectionExtensions_QuerySingleOrDefaultTests; -public abstract class - DbConnectionExtensions_QuerySingleOrDefaultTests - : IntegrationTestsBase +public abstract class DbConnectionExtensions_QuerySingleOrDefaultTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { [Theory] @@ -50,7 +44,8 @@ await Invoking(() => cancellationToken: cancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); } @@ -98,17 +93,15 @@ bool useAsyncApi EntityAssertions.AssertDataRowMatchesEntity(dataRow!, entity); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingleOrDefault_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - bool useAsyncApi - ) + public async Task QuerySingleOrDefault_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -170,31 +163,34 @@ public async Task QuerySingleOrDefault_QueryReturnedMoreThanOneRow_ShouldThrow(b { this.CreateEntitiesInDb(2); - await Invoking(() => CallApi( + await Invoking(() => + CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() - .WithMessage( - "The SQL statement did return more than one row." - ); + .Should() + .ThrowAsync() + .WithMessage("The SQL statement did return more than one row."); } - [Theory] [InlineData(false)] [InlineData(true)] public async Task QuerySingleOrDefault_QueryReturnedNoRows_ShouldReturnNull(bool useAsyncApi) => - ((object?)await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("Entity")} WHERE {Q("Id")} = -1", - cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeNull(); + ( + (object?) + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("Entity")} WHERE {Q("Id")} = -1", + cancellationToken: TestContext.Current.CancellationToken + ) + ) + .Should() + .BeNull(); [Theory] [InlineData(false)] @@ -218,23 +214,19 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ); - dataRow - .Should().NotBeNull(); + dataRow.Should().NotBeNull(); - dataRow["Id"] - .Should().Be(entityId); + dataRow["Id"].Should().Be(entityId); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingleOrDefault_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - bool useAsyncApi - ) + public async Task QuerySingleOrDefault_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -247,8 +239,7 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ); - ValueConverter.ConvertValueToType(dataRow!["Id"]) - .Should().Be(entityId); + ValueConverter.ConvertValueToType(dataRow!["Id"]).Should().Be(entityId); } [Theory] @@ -290,13 +281,17 @@ public async Task QuerySingleOrDefault_Transaction_ShouldUseTransaction(bool use await transaction.RollbackAsync(); } - ((object?)await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("Entity")}", - cancellationToken: TestContext.Current.CancellationToken - )) - .Should().BeNull(); + ( + (object?) + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("Entity")}", + cancellationToken: TestContext.Current.CancellationToken + ) + ) + .Should() + .BeNull(); } private static Task CallApi( @@ -323,13 +318,7 @@ public async Task QuerySingleOrDefault_Transaction_ShouldUseTransaction(bool use try { return Task.FromResult( - connection.QuerySingleOrDefault( - statement, - transaction, - commandTimeout, - commandType, - cancellationToken - ) + connection.QuerySingleOrDefault(statement, transaction, commandTimeout, commandType, cancellationToken) ); } catch (Exception ex) diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleTests.cs index f65e3ff..72f59e8 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QuerySingleTests.cs @@ -4,28 +4,23 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests; -public sealed class - DbConnectionExtensions_QuerySingleTests_MySql : - DbConnectionExtensions_QuerySingleTests; +public sealed class DbConnectionExtensions_QuerySingleTests_MySql + : DbConnectionExtensions_QuerySingleTests; -public sealed class - DbConnectionExtensions_QuerySingleTests_Oracle : - DbConnectionExtensions_QuerySingleTests; +public sealed class DbConnectionExtensions_QuerySingleTests_Oracle + : DbConnectionExtensions_QuerySingleTests; -public sealed class - DbConnectionExtensions_QuerySingleTests_PostgreSql : - DbConnectionExtensions_QuerySingleTests; +public sealed class DbConnectionExtensions_QuerySingleTests_PostgreSql + : DbConnectionExtensions_QuerySingleTests; -public sealed class - DbConnectionExtensions_QuerySingleTests_Sqlite : - DbConnectionExtensions_QuerySingleTests; +public sealed class DbConnectionExtensions_QuerySingleTests_Sqlite + : DbConnectionExtensions_QuerySingleTests; -public sealed class - DbConnectionExtensions_QuerySingleTests_SqlServer : - DbConnectionExtensions_QuerySingleTests; +public sealed class DbConnectionExtensions_QuerySingleTests_SqlServer + : DbConnectionExtensions_QuerySingleTests; -public abstract class - DbConnectionExtensions_QuerySingleTests : IntegrationTestsBase +public abstract class DbConnectionExtensions_QuerySingleTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { [Theory] @@ -47,7 +42,8 @@ await Invoking(() => cancellationToken: cancellationToken ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); } @@ -74,9 +70,7 @@ public async Task QuerySingle_CommandType_ShouldUseCommandType(bool useAsyncApi) [Theory] [InlineData(false)] [InlineData(true)] - public async Task QuerySingle_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution( - bool useAsyncApi - ) + public async Task QuerySingle_ComplexObjectsTemporaryTable_ShouldDropTemporaryTableAfterExecution(bool useAsyncApi) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -95,17 +89,15 @@ bool useAsyncApi EntityAssertions.AssertDataRowMatchesEntity(dataRow, entity); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingle_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( - bool useAsyncApi - ) + public async Task QuerySingle_ComplexObjectsTemporaryTable_ShouldPassInterpolatedObjectsAsMultiColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -167,35 +159,34 @@ public async Task QuerySingle_QueryReturnedMoreThanOneRow_ShouldThrow(bool useAs { this.CreateEntitiesInDb(2); - await Invoking(() => CallApi( + await Invoking(() => + CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() - .WithMessage( - "The SQL statement did return more than one row." - ); + .Should() + .ThrowAsync() + .WithMessage("The SQL statement did return more than one row."); } - [Theory] [InlineData(false)] [InlineData(true)] public Task QuerySingle_QueryReturnedNoRows_ShouldThrow(bool useAsyncApi) => - Invoking(() => CallApi( + Invoking(() => + CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")} WHERE {Q("Id")} = -1", cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync() - .WithMessage( - "The SQL statement did not return any rows." - ); + .Should() + .ThrowAsync() + .WithMessage("The SQL statement did not return any rows."); [Theory] [InlineData(false)] @@ -217,23 +208,19 @@ public async Task QuerySingle_ScalarValuesTemporaryTable_ShouldDropTemporaryTabl cancellationToken: TestContext.Current.CancellationToken ); - dataRow - .Should().NotBeNull(); + dataRow.Should().NotBeNull(); - dataRow["Id"] - .Should().Be(entityId); + dataRow["Id"].Should().Be(entityId); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - QuerySingle_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( - bool useAsyncApi - ) + public async Task QuerySingle_ScalarValuesTemporaryTable_ShouldPassInterpolatedValuesAsSingleColumnTemporaryTable( + bool useAsyncApi + ) { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -246,8 +233,7 @@ bool useAsyncApi cancellationToken: TestContext.Current.CancellationToken ); - ValueConverter.ConvertValueToType(dataRow["Id"]) - .Should().Be(entityId); + ValueConverter.ConvertValueToType(dataRow["Id"]).Should().Be(entityId); } [Theory] @@ -289,14 +275,16 @@ public async Task QuerySingle_Transaction_ShouldUseTransaction(bool useAsyncApi) await transaction.RollbackAsync(); } - await Invoking(() => CallApi( + await Invoking(() => + CallApi( useAsyncApi, this.Connection, $"SELECT * FROM {Q("Entity")}", cancellationToken: TestContext.Current.CancellationToken ) ) - .Should().ThrowAsync(); + .Should() + .ThrowAsync(); } private static Task CallApi( @@ -311,25 +299,13 @@ private static Task CallApi( { if (useAsyncApi) { - return connection.QuerySingleAsync( - statement, - transaction, - commandTimeout, - commandType, - cancellationToken - ); + return connection.QuerySingleAsync(statement, transaction, commandTimeout, commandType, cancellationToken); } try { return Task.FromResult( - connection.QuerySingle( - statement, - transaction, - commandTimeout, - commandType, - cancellationToken - ) + connection.QuerySingle(statement, transaction, commandTimeout, commandType, cancellationToken) ); } catch (Exception ex) diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryTests.cs index d6ebcee..9f1d5d2 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.QueryTests.cs @@ -4,28 +4,23 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests; -public sealed class - DbConnectionExtensions_QueryTests_MySql : - DbConnectionExtensions_QueryTests; +public sealed class DbConnectionExtensions_QueryTests_MySql + : DbConnectionExtensions_QueryTests; -public sealed class - DbConnectionExtensions_QueryTests_Oracle : - DbConnectionExtensions_QueryTests; +public sealed class DbConnectionExtensions_QueryTests_Oracle + : DbConnectionExtensions_QueryTests; -public sealed class - DbConnectionExtensions_QueryTests_PostgreSql : - DbConnectionExtensions_QueryTests; +public sealed class DbConnectionExtensions_QueryTests_PostgreSql + : DbConnectionExtensions_QueryTests; -public sealed class - DbConnectionExtensions_QueryTests_Sqlite : - DbConnectionExtensions_QueryTests; +public sealed class DbConnectionExtensions_QueryTests_Sqlite + : DbConnectionExtensions_QueryTests; -public sealed class - DbConnectionExtensions_QueryTests_SqlServer : - DbConnectionExtensions_QueryTests; +public sealed class DbConnectionExtensions_QueryTests_SqlServer + : DbConnectionExtensions_QueryTests; -public abstract class - DbConnectionExtensions_QueryTests : IntegrationTestsBase +public abstract class DbConnectionExtensions_QueryTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { [Theory] @@ -41,13 +36,16 @@ public async Task Query_CancellationToken_ShouldCancelOperationIfCancellationIsR await Invoking(() => CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("Entity")}", - cancellationToken: cancellationToken - ).ToListAsync(cancellationToken).AsTask() + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("Entity")}", + cancellationToken: cancellationToken + ) + .ToListAsync(cancellationToken) + .AsTask() ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); } @@ -61,12 +59,13 @@ public async Task Query_CommandType_ShouldUseCommandType(bool useAsyncApi) var entities = this.CreateEntitiesInDb(); var dataRows = await CallApi( - useAsyncApi, - this.Connection, - "GetEntities", - commandType: CommandType.StoredProcedure, - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken); + useAsyncApi, + this.Connection, + "GetEntities", + commandType: CommandType.StoredProcedure, + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken); EntityAssertions.AssertDataRowsMatchEntities(dataRows, entities); } @@ -87,31 +86,27 @@ bool useAsyncApi var temporaryTableName = statement.TemporaryTables[0].Name; var enumerator = CallApi( - useAsyncApi, - this.Connection, - statement, - cancellationToken: TestContext.Current.CancellationToken - ).GetAsyncEnumerator(); + useAsyncApi, + this.Connection, + statement, + cancellationToken: TestContext.Current.CancellationToken + ) + .GetAsyncEnumerator(); - (await enumerator.MoveNextAsync()) - .Should().BeTrue(); + (await enumerator.MoveNextAsync()).Should().BeTrue(); if (this.TestDatabaseProvider.SupportsCommandExecutionWhileDataReaderIsOpen) { - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeTrue(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeTrue(); } - (await enumerator.MoveNextAsync()) - .Should().BeTrue(); + (await enumerator.MoveNextAsync()).Should().BeTrue(); - (await enumerator.MoveNextAsync()) - .Should().BeFalse(); + (await enumerator.MoveNextAsync()).Should().BeFalse(); await enumerator.DisposeAsync(); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] @@ -126,11 +121,12 @@ bool useAsyncApi var entities = Generate.Multiple(); var dataRows = await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {TemporaryTable(entities)}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken); + useAsyncApi, + this.Connection, + $"SELECT * FROM {TemporaryTable(entities)}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken); EntityAssertions.AssertDataRowsMatchEntities(dataRows, entities); } @@ -143,11 +139,12 @@ public async Task Query_InterpolatedParameter_ShouldPassInterpolatedParameter(bo var entity = this.CreateEntityInDb(); var dataRows = await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("Entity")} WHERE {Q("Id")} = {Parameter(entity.Id)}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken); + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("Entity")} WHERE {Q("Id")} = {Parameter(entity.Id)}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken); EntityAssertions.AssertDataRowsMatchEntities(dataRows, [entity]); } @@ -165,11 +162,12 @@ public async Task Query_Parameter_ShouldPassParameter(bool useAsyncApi) ); var dataRows = await CallApi( - useAsyncApi, - this.Connection, - statement, - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken); + useAsyncApi, + this.Connection, + statement, + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken); EntityAssertions.AssertDataRowsMatchEntities(dataRows, [entity]); } @@ -190,31 +188,27 @@ bool useAsyncApi var temporaryTableName = statement.TemporaryTables[0].Name; var enumerator = CallApi( - useAsyncApi, - this.Connection, - statement, - cancellationToken: TestContext.Current.CancellationToken - ).GetAsyncEnumerator(); + useAsyncApi, + this.Connection, + statement, + cancellationToken: TestContext.Current.CancellationToken + ) + .GetAsyncEnumerator(); - (await enumerator.MoveNextAsync()) - .Should().BeTrue(); + (await enumerator.MoveNextAsync()).Should().BeTrue(); if (this.TestDatabaseProvider.SupportsCommandExecutionWhileDataReaderIsOpen) { - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeTrue(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeTrue(); } - (await enumerator.MoveNextAsync()) - .Should().BeTrue(); + (await enumerator.MoveNextAsync()).Should().BeTrue(); - (await enumerator.MoveNextAsync()) - .Should().BeFalse(); + (await enumerator.MoveNextAsync()).Should().BeFalse(); await enumerator.DisposeAsync(); - this.ExistsTemporaryTableInDb(temporaryTableName) - .Should().BeFalse(); + this.ExistsTemporaryTableInDb(temporaryTableName).Should().BeFalse(); } [Theory] @@ -229,16 +223,16 @@ bool useAsyncApi var entityIds = Generate.Ids(); var dataRows = await CallApi( - useAsyncApi, - this.Connection, - $"SELECT {Q("Value")} AS {Q("Id")} FROM {TemporaryTable(entityIds)}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken); + useAsyncApi, + this.Connection, + $"SELECT {Q("Value")} AS {Q("Id")} FROM {TemporaryTable(entityIds)}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken); for (var i = 0; i < entityIds.Count; i++) { - ValueConverter.ConvertValueToType(dataRows[i]["Id"]) - .Should().Be(entityIds[i]); + ValueConverter.ConvertValueToType(dataRows[i]["Id"]).Should().Be(entityIds[i]); } } @@ -250,11 +244,12 @@ public async Task Query_ShouldReturnDataRowsForQueryResult(bool useAsyncApi) var entities = this.CreateEntitiesInDb(); var dataRows = await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("Entity")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken); + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("Entity")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken); EntityAssertions.AssertDataRowsMatchEntities(dataRows, entities); } @@ -269,25 +264,30 @@ public async Task Query_Transaction_ShouldUseTransaction(bool useAsyncApi) var entities = this.CreateEntitiesInDb(null, transaction); var dataRows = await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("Entity")}", - transaction, - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken); + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("Entity")}", + transaction, + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken); EntityAssertions.AssertDataRowsMatchEntities(dataRows, entities); await transaction.RollbackAsync(); } - (await CallApi( - useAsyncApi, - this.Connection, - $"SELECT * FROM {Q("Entity")}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEmpty(); + ( + await CallApi( + useAsyncApi, + this.Connection, + $"SELECT * FROM {Q("Entity")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEmpty(); } private static IAsyncEnumerable CallApi( @@ -302,21 +302,11 @@ private static IAsyncEnumerable CallApi( { if (useAsyncApi) { - return connection.QueryAsync( - statement, - transaction, - commandTimeout, - commandType, - cancellationToken - ); + return connection.QueryAsync(statement, transaction, commandTimeout, commandType, cancellationToken); } - return connection.Query( - statement, - transaction, - commandTimeout, - commandType, - cancellationToken - ).ToAsyncEnumerable(); + return connection + .Query(statement, transaction, commandTimeout, commandType, cancellationToken) + .ToAsyncEnumerable(); } } diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.TemporaryTableTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.TemporaryTableTests.cs index 7f9e492..6b48a3d 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.TemporaryTableTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.TemporaryTableTests.cs @@ -1,28 +1,23 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests; -public sealed class - DbConnectionExtensions_TemporaryTableTests_MySql : - DbConnectionExtensions_TemporaryTableTests; +public sealed class DbConnectionExtensions_TemporaryTableTests_MySql + : DbConnectionExtensions_TemporaryTableTests; -public sealed class - DbConnectionExtensions_TemporaryTableTests_PostgreSql : - DbConnectionExtensions_TemporaryTableTests; +public sealed class DbConnectionExtensions_TemporaryTableTests_PostgreSql + : DbConnectionExtensions_TemporaryTableTests; -public sealed class - DbConnectionExtensions_TemporaryTableTests_Sqlite : - DbConnectionExtensions_TemporaryTableTests; +public sealed class DbConnectionExtensions_TemporaryTableTests_Sqlite + : DbConnectionExtensions_TemporaryTableTests; -public sealed class - DbConnectionExtensions_TemporaryTableTests_SqlServer : - DbConnectionExtensions_TemporaryTableTests; +public sealed class DbConnectionExtensions_TemporaryTableTests_SqlServer + : DbConnectionExtensions_TemporaryTableTests; -public abstract class - DbConnectionExtensions_TemporaryTableTests : IntegrationTestsBase +public abstract class DbConnectionExtensions_TemporaryTableTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { [Fact] - public void - TemporaryTable_ComplexObjects_EnumProperty_EnumSerializationModeIsIntegers_ShouldSerializeEnumToInteger() + public void TemporaryTable_ComplexObjects_EnumProperty_EnumSerializationModeIsIntegers_ShouldSerializeEnumToInteger() { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -34,7 +29,8 @@ public void $"SELECT {Q("Enum")} FROM {TemporaryTable(entities)}", cancellationToken: TestContext.Current.CancellationToken ) - .Should().BeEquivalentTo(entities.Select(a => (int)a.Enum)); + .Should() + .BeEquivalentTo(entities.Select(a => (int)a.Enum)); } [Fact] @@ -50,7 +46,8 @@ public void TemporaryTable_ComplexObjects_EnumProperty_EnumSerializationModeIsSt $"SELECT {Q("Enum")} FROM {TemporaryTable(entities)}", cancellationToken: TestContext.Current.CancellationToken ) - .Should().BeEquivalentTo(entities.Select(a => a.Enum.ToString())); + .Should() + .BeEquivalentTo(entities.Select(a => a.Enum.ToString())); } [Fact] @@ -64,7 +61,8 @@ public void TemporaryTable_ComplexObjects_ShouldBePassedAsMultiColumnTemporaryTa $"SELECT * FROM {TemporaryTable(entities)}", cancellationToken: TestContext.Current.CancellationToken ) - .Should().BeEquivalentTo(entities); + .Should() + .BeEquivalentTo(entities); } [Fact] @@ -76,12 +74,12 @@ public void TemporaryTable_ScalarValues_Enums_EnumSerializationModeIsIntegers_Sh var enumValues = Generate.Multiple(); - this.Connection - .Query( + this.Connection.Query( $"SELECT {Q("Value")} FROM {TemporaryTable(enumValues)}", cancellationToken: TestContext.Current.CancellationToken ) - .Should().BeEquivalentTo(enumValues.Select(a => (int)a)); + .Should() + .BeEquivalentTo(enumValues.Select(a => (int)a)); } [Fact] @@ -93,12 +91,12 @@ public void TemporaryTable_ScalarValues_Enums_EnumSerializationModeIsStrings_Sho var enumValues = Generate.Multiple(); - this.Connection - .Query( + this.Connection.Query( $"SELECT {Q("Value")} FROM {TemporaryTable(enumValues)}", cancellationToken: TestContext.Current.CancellationToken ) - .Should().BeEquivalentTo(enumValues.Select(a => a.ToString())); + .Should() + .BeEquivalentTo(enumValues.Select(a => a.ToString())); } [Fact] @@ -108,17 +106,16 @@ public void TemporaryTable_ScalarValues_ShouldBePassedAsSingleColumnTemporaryTab var entityIds = Generate.Ids(); - this.Connection - .Query( + this.Connection.Query( $"SELECT {Q("Value")} FROM {TemporaryTable(entityIds)}", cancellationToken: TestContext.Current.CancellationToken ) - .Should().BeEquivalentTo(entityIds); + .Should() + .BeEquivalentTo(entityIds); } [Fact] - public async Task - TemporaryTableAsync_ComplexObjects_EnumProperty_EnumSerializationModeIsIntegers_ShouldSerializeEnumToInteger() + public async Task TemporaryTableAsync_ComplexObjects_EnumProperty_EnumSerializationModeIsIntegers_ShouldSerializeEnumToInteger() { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -126,16 +123,20 @@ public async Task var entities = Generate.Multiple(); - (await this.Connection.QueryAsync( - $"SELECT {Q("Enum")} FROM {TemporaryTable(entities)}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities.Select(a => (int)a.Enum)); + ( + await this + .Connection.QueryAsync( + $"SELECT {Q("Enum")} FROM {TemporaryTable(entities)}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities.Select(a => (int)a.Enum)); } [Fact] - public async Task - TemporaryTableAsync_ComplexObjects_EnumProperty_EnumSerializationModeIsStrings_ShouldSerializeEnumToString() + public async Task TemporaryTableAsync_ComplexObjects_EnumProperty_EnumSerializationModeIsStrings_ShouldSerializeEnumToString() { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -143,11 +144,16 @@ public async Task var entities = Generate.Multiple(); - (await this.Connection.QueryAsync( - $"SELECT {Q("Enum")} FROM {TemporaryTable(entities)}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities.Select(a => a.Enum.ToString())); + ( + await this + .Connection.QueryAsync( + $"SELECT {Q("Enum")} FROM {TemporaryTable(entities)}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities.Select(a => a.Enum.ToString())); } [Fact] @@ -157,16 +163,20 @@ public async Task TemporaryTableAsync_ComplexObjects_ShouldBePassedAsMultiColumn var entities = Generate.Multiple(); - (await this.Connection.QueryAsync( - $"SELECT * FROM {TemporaryTable(entities)}", - cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entities); + ( + await this + .Connection.QueryAsync( + $"SELECT * FROM {TemporaryTable(entities)}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entities); } [Fact] - public async Task - TemporaryTableAsync_ScalarValues_Enums_EnumSerializationModeIsIntegers_ShouldSerializeEnumToInteger() + public async Task TemporaryTableAsync_ScalarValues_Enums_EnumSerializationModeIsIntegers_ShouldSerializeEnumToInteger() { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -174,17 +184,20 @@ public async Task var enumValues = Generate.Multiple(); - (await this.Connection - .QueryAsync( + ( + await this + .Connection.QueryAsync( $"SELECT {Q("Value")} FROM {TemporaryTable(enumValues)}", cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(enumValues.Select(a => (int)a)); + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(enumValues.Select(a => (int)a)); } [Fact] - public async Task - TemporaryTableAsync_ScalarValues_Enums_EnumSerializationModeIsStrings_ShouldSerializeEnumToString() + public async Task TemporaryTableAsync_ScalarValues_Enums_EnumSerializationModeIsStrings_ShouldSerializeEnumToString() { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -192,12 +205,16 @@ public async Task var enumValues = Generate.Multiple(); - (await this.Connection - .QueryAsync( + ( + await this + .Connection.QueryAsync( $"SELECT {Q("Value")} FROM {TemporaryTable(enumValues)}", cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(enumValues.Select(a => a.ToString())); + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(enumValues.Select(a => a.ToString())); } [Fact] @@ -207,11 +224,15 @@ public async Task TemporaryTableAsync_ScalarValues_ShouldBePassedAsSingleColumnT var entityIds = Generate.Ids(); - (await this.Connection - .QueryAsync( + ( + await this + .Connection.QueryAsync( $"SELECT {Q("Value")} FROM {TemporaryTable(entityIds)}", cancellationToken: TestContext.Current.CancellationToken - ).ToListAsync(TestContext.Current.CancellationToken)) - .Should().BeEquivalentTo(entityIds); + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(entityIds); } } diff --git a/tests/DbConnectionPlus.IntegrationTests/GlobalUsings.cs b/tests/DbConnectionPlus.IntegrationTests/GlobalUsings.cs index 5c98443..68c98e3 100644 --- a/tests/DbConnectionPlus.IntegrationTests/GlobalUsings.cs +++ b/tests/DbConnectionPlus.IntegrationTests/GlobalUsings.cs @@ -1,12 +1,12 @@ global using System.Data; -global using Xunit; global using AwesomeAssertions; +global using static AwesomeAssertions.FluentActions; global using Microsoft.Data.SqlClient; global using RentADeveloper.DbConnectionPlus.Configuration; global using RentADeveloper.DbConnectionPlus.DbCommands; +global using static RentADeveloper.DbConnectionPlus.DbConnectionExtensions; global using RentADeveloper.DbConnectionPlus.IntegrationTests.TestDatabase; global using RentADeveloper.DbConnectionPlus.SqlStatements; global using RentADeveloper.DbConnectionPlus.UnitTests.TestData; +global using Xunit; global using DataRow = RentADeveloper.DbConnectionPlus.Dynamic.DataRow; -global using static AwesomeAssertions.FluentActions; -global using static RentADeveloper.DbConnectionPlus.DbConnectionExtensions; diff --git a/tests/DbConnectionPlus.IntegrationTests/IntegrationTestsBase.cs b/tests/DbConnectionPlus.IntegrationTests/IntegrationTestsBase.cs index 45a09ec..d58d06f 100644 --- a/tests/DbConnectionPlus.IntegrationTests/IntegrationTestsBase.cs +++ b/tests/DbConnectionPlus.IntegrationTests/IntegrationTestsBase.cs @@ -31,7 +31,9 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests; /// that before this constructor opens a connection to it. /// public abstract class IntegrationTestsBase - : IClassFixture>, IDisposable, IAsyncDisposable + : IClassFixture>, + IDisposable, + IAsyncDisposable where TTestDatabaseProvider : ITestDatabaseProvider, new() { protected IntegrationTestsBase() @@ -39,8 +41,9 @@ protected IntegrationTestsBase() // Ensure consistent culture for tests. CultureInfo.CurrentCulture = CultureInfo.CurrentUICulture = - Thread.CurrentThread.CurrentCulture = - Thread.CurrentThread.CurrentUICulture = new("en-US"); + Thread.CurrentThread.CurrentCulture = + Thread.CurrentThread.CurrentUICulture = + new("en-US"); this.logDbCommands = false; @@ -48,12 +51,14 @@ protected IntegrationTestsBase() DbConnectionPlusConfiguration.Instance = new() { EnumSerializationMode = EnumSerializationMode.Strings, - InterceptDbCommand = this.InterceptDbCommand + InterceptDbCommand = this.InterceptDbCommand, }; DbConnectionPlusConfiguration.Instance.RegisterDatabaseAdapter(new MySqlDatabaseAdapter()); DbConnectionPlusConfiguration.Instance.RegisterDatabaseAdapter(new OracleDatabaseAdapter()); - DbConnectionPlusConfiguration.Instance.RegisterDatabaseAdapter(new PostgreSqlDatabaseAdapter()); + DbConnectionPlusConfiguration.Instance.RegisterDatabaseAdapter( + new PostgreSqlDatabaseAdapter() + ); DbConnectionPlusConfiguration.Instance.RegisterDatabaseAdapter(new SqliteDatabaseAdapter()); DbConnectionPlusConfiguration.Instance.RegisterDatabaseAdapter(new SqlServerDatabaseAdapter()); @@ -108,8 +113,7 @@ public async ValueTask DisposeAsync() /// The formatted parameter name, including the appropriate prefix, suitable for inclusion in SQL statements. /// /// The name of this method is intentionally kept very short, so test code doesn't get bloated. - public static string P(string parameterName) => - currentDatabaseAdapter.Value!.FormatParameterName(parameterName); + public static string P(string parameterName) => currentDatabaseAdapter.Value!.FormatParameterName(parameterName); /// /// Returns the specified database identifier properly quoted for use in SQL statements according to the current @@ -118,8 +122,7 @@ public static string P(string parameterName) => /// The identifier to quote. /// The quoted identifier, suitable for inclusion in SQL statements. /// The name of this method is intentionally kept very short, so test code doesn't get bloated. - public static string Q(string identifier) => - currentDatabaseAdapter.Value!.QuoteIdentifier(identifier); + public static string Q(string identifier) => currentDatabaseAdapter.Value!.QuoteIdentifier(identifier); /// /// Returns the specified temporary table name properly quoted for use in SQL statements according to the current @@ -129,10 +132,7 @@ public static string Q(string identifier) => /// The quoted temporary table name, suitable for inclusion in SQL statements. /// The name of this method is intentionally kept very short, so test code doesn't get bloated. public static string QT(string tableName) => - currentDatabaseAdapter.Value!.QuoteTemporaryTableName( - tableName, - currentTestDatabaseConnection.Value! - ); + currentDatabaseAdapter.Value!.QuoteTemporaryTableName(tableName, currentTestDatabaseConnection.Value!); /// /// The connection to the test database. @@ -163,25 +163,19 @@ public static string QT(string tableName) => protected List CreateEntitiesInDb(int? numberOfEntities = null, DbTransaction? transaction = null) where T : class => this.ExecuteWithoutDbCommandLogging(() => - { - var entities = Generate.Multiple(numberOfEntities); + { + var entities = Generate.Multiple(numberOfEntities); - this.Connection.InsertEntities( - entities, - transaction, - TestContext.Current.CancellationToken - ); + this.Connection.InsertEntities(entities, transaction, TestContext.Current.CancellationToken); - foreach (var entity in entities) - { - // Verify that the entity has been inserted: - this.ExistsEntityInDb(entity, transaction) - .Should().BeTrue(); - } - - return entities; + foreach (var entity in entities) + { + // Verify that the entity has been inserted: + this.ExistsEntityInDb(entity, transaction).Should().BeTrue(); } - ); + + return entities; + }); /// /// Creates an entity of the type and inserts it into the test database. @@ -190,25 +184,18 @@ protected List CreateEntitiesInDb(int? numberOfEntities = null, DbTransact /// The database transaction within to perform the operation. /// The entity that was created and inserted. protected T CreateEntityInDb(DbTransaction? transaction = null) - where T : class - => - this.ExecuteWithoutDbCommandLogging(() => - { - var entity = Generate.Single(); + where T : class => + this.ExecuteWithoutDbCommandLogging(() => + { + var entity = Generate.Single(); - this.Connection.InsertEntity( - entity, - transaction, - TestContext.Current.CancellationToken - ); + this.Connection.InsertEntity(entity, transaction, TestContext.Current.CancellationToken); - // Verify that the entity has been inserted: - this.ExistsEntityInDb(entity, transaction) - .Should().BeTrue(); + // Verify that the entity has been inserted: + this.ExistsEntityInDb(entity, transaction).Should().BeTrue(); - return entity; - } - ); + return entity; + }); /// /// Determines whether an entity having the key(s) of the specified entity exists in the test database. @@ -244,11 +231,8 @@ SELECT 1 keyProperties.Select(p => (p.PropertyName, p.PropertyGetter!(entity))).ToArray()! ); - return this.ExecuteWithoutDbCommandLogging(() => this.Connection.Exists( - statement, - transaction, - cancellationToken: TestContext.Current.CancellationToken - ) + return this.ExecuteWithoutDbCommandLogging(() => + this.Connection.Exists(statement, transaction, cancellationToken: TestContext.Current.CancellationToken) ); } @@ -263,11 +247,7 @@ SELECT 1 /// protected bool ExistsTemporaryTableInDb(string tableName, DbTransaction? transaction = null) => this.ExecuteWithoutDbCommandLogging(() => - this.TestDatabaseProvider.ExistsTemporaryTable( - tableName, - this.Connection, - transaction - ) + this.TestDatabaseProvider.ExistsTemporaryTable(tableName, this.Connection, transaction) ); /// @@ -291,16 +271,9 @@ protected string GetCollationOfTemporaryTableColumn(string temporaryTableName, s /// The name of the temporary table that contains the specified column. /// The name of the column of which to get the data type. /// The data type of the specified column of the specified temporary table. - protected string GetDataTypeOfTemporaryTableColumn( - string temporaryTableName, - string columnName - ) => + protected string GetDataTypeOfTemporaryTableColumn(string temporaryTableName, string columnName) => this.ExecuteWithoutDbCommandLogging(() => - this.TestDatabaseProvider.GetDataTypeOfTemporaryTableColumn( - temporaryTableName, - columnName, - this.Connection - ) + this.TestDatabaseProvider.GetDataTypeOfTemporaryTableColumn(temporaryTableName, columnName, this.Connection) ); /// diff --git a/tests/DbConnectionPlus.IntegrationTests/Readers/CommandDisposingDataReaderDecoratorTests.cs b/tests/DbConnectionPlus.IntegrationTests/Readers/CommandDisposingDataReaderDecoratorTests.cs index 67facb9..b6017b8 100644 --- a/tests/DbConnectionPlus.IntegrationTests/Readers/CommandDisposingDataReaderDecoratorTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/Readers/CommandDisposingDataReaderDecoratorTests.cs @@ -2,28 +2,23 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.Readers; -public sealed class - CommandDisposingDataReaderDecoratorTests_MySql : - CommandDisposingDataReaderDecoratorTests; +public sealed class CommandDisposingDataReaderDecoratorTests_MySql + : CommandDisposingDataReaderDecoratorTests; -public sealed class - CommandDisposingDataReaderDecoratorTests_Oracle : - CommandDisposingDataReaderDecoratorTests; +public sealed class CommandDisposingDataReaderDecoratorTests_Oracle + : CommandDisposingDataReaderDecoratorTests; -public sealed class - CommandDisposingDataReaderDecoratorTests_PostgreSql : - CommandDisposingDataReaderDecoratorTests; +public sealed class CommandDisposingDataReaderDecoratorTests_PostgreSql + : CommandDisposingDataReaderDecoratorTests; -public sealed class - CommandDisposingDataReaderDecoratorTests_Sqlite : - CommandDisposingDataReaderDecoratorTests; +public sealed class CommandDisposingDataReaderDecoratorTests_Sqlite + : CommandDisposingDataReaderDecoratorTests; -public sealed class - CommandDisposingDataReaderDecoratorTests_SqlServer : - CommandDisposingDataReaderDecoratorTests; +public sealed class CommandDisposingDataReaderDecoratorTests_SqlServer + : CommandDisposingDataReaderDecoratorTests; -public abstract class - CommandDisposingDataReaderDecoratorTests : IntegrationTestsBase +public abstract class CommandDisposingDataReaderDecoratorTests + : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { [Fact] @@ -43,13 +38,12 @@ public void Read_OperationCancelledViaCancellationToken_ShouldThrowOperationCanc var cancellationToken = cancellationTokenSource.Token; ThreadPool.QueueUserWorkItem(_ => - { - Thread.Sleep(100); - cancellationTokenSource.Cancel(); - // ReSharper disable once AccessToDisposedClosure - command.Cancel(); - } - ); + { + Thread.Sleep(100); + cancellationTokenSource.Cancel(); + // ReSharper disable once AccessToDisposedClosure + command.Cancel(); + }); var commandDisposer = new DbCommandDisposer(command, [], default); @@ -63,13 +57,13 @@ public void Read_OperationCancelledViaCancellationToken_ShouldThrowOperationCanc ); // Read the value from before the delay: - decorator.Read() - .Should().BeTrue(); + decorator.Read().Should().BeTrue(); // The next read should be cancelled: // ReSharper disable once AccessToDisposedClosure Invoking(() => decorator.Read()) - .Should().Throw() + .Should() + .Throw() .Where(a => a.CancellationToken == cancellationToken); } @@ -90,13 +84,12 @@ public async Task ReadAsync_OperationCancelledViaCancellationToken_ShouldThrowOp var cancellationToken = cancellationTokenSource.Token; ThreadPool.QueueUserWorkItem(_ => - { - Thread.Sleep(100); - cancellationTokenSource.Cancel(); - // ReSharper disable once AccessToDisposedClosure - command.Cancel(); - } - ); + { + Thread.Sleep(100); + cancellationTokenSource.Cancel(); + // ReSharper disable once AccessToDisposedClosure + command.Cancel(); + }); var commandDisposer = new DbCommandDisposer(command, [], default); @@ -111,12 +104,14 @@ public async Task ReadAsync_OperationCancelledViaCancellationToken_ShouldThrowOp // Read the value from before the delay: (await decorator.ReadAsync(TestContext.Current.CancellationToken)) - .Should().BeTrue(); + .Should() + .BeTrue(); // The next read should be cancelled: // ReSharper disable once AccessToDisposedClosure await Invoking(() => decorator.ReadAsync(cancellationToken)) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); } } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/MySqlContainerFixture.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/MySqlContainerFixture.cs index f01390f..bcf9bbe 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/MySqlContainerFixture.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/MySqlContainerFixture.cs @@ -12,7 +12,8 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.TestDatabase.Containe /// Runs the MySQL server the MySQL integration tests use in a Docker container. /// internal sealed class MySqlContainerFixture() - : DbContainerFixture(TestDatabaseDiagnosticMessageSink.Instance), ITestDatabaseContainerFixture + : DbContainerFixture(TestDatabaseDiagnosticMessageSink.Instance), + ITestDatabaseContainerFixture { /// public override string ConnectionString => @@ -25,12 +26,11 @@ internal sealed class MySqlContainerFixture() // MySqlTemporaryTableBuilder fills temporary tables with MySqlBulkCopy, which is LOAD DATA LOCAL // INFILE underneath and refuses to run unless the client allows it. - AllowLoadLocalInfile = true + AllowLoadLocalInfile = true, }.ConnectionString; /// - public override DbProviderFactory DbProviderFactory => - MySqlConnectorFactory.Instance; + public override DbProviderFactory DbProviderFactory => MySqlConnectorFactory.Instance; /// protected override MySqlBuilder Configure() => diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/OracleContainerFixture.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/OracleContainerFixture.cs index dd5ebfb..ac9dd4a 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/OracleContainerFixture.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/OracleContainerFixture.cs @@ -12,7 +12,8 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.TestDatabase.Containe /// Runs the Oracle server the Oracle integration tests use in a Docker container. /// internal sealed class OracleContainerFixture() - : DbContainerFixture(TestDatabaseDiagnosticMessageSink.Instance), ITestDatabaseContainerFixture + : DbContainerFixture(TestDatabaseDiagnosticMessageSink.Instance), + ITestDatabaseContainerFixture { /// /// @@ -25,26 +26,23 @@ internal sealed class OracleContainerFixture() { DataSource = $"{this.Container.Hostname}:{this.MappedPort}/{ServiceName}", UserID = SystemUsername, - Password = TestDatabaseContainers.Password + Password = TestDatabaseContainers.Password, }.ConnectionString; /// - public override DbProviderFactory DbProviderFactory => - OracleClientFactory.Instance; + public override DbProviderFactory DbProviderFactory => OracleClientFactory.Instance; /// protected override OracleBuilder Configure() => // WithDatabase is deliberately not called: for an Oracle 18+ image the module would only pass the name // on to ORACLE_DATABASE if it differed from the pluggable database the image already ships, and asking // this one to create a second FREEPDB1 fails. - new OracleBuilder(Image) - .WithPassword(TestDatabaseContainers.Password); + new OracleBuilder(Image).WithPassword(TestDatabaseContainers.Password); /// /// The host port the container's Oracle listener is published on. /// - private ushort MappedPort => - this.Container.GetMappedPublicPort(OracleBuilder.OraclePort); + private ushort MappedPort => this.Container.GetMappedPublicPort(OracleBuilder.OraclePort); /// /// The image the container runs. diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/PostgreSqlContainerFixture.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/PostgreSqlContainerFixture.cs index 77c19a1..b954f86 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/PostgreSqlContainerFixture.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/PostgreSqlContainerFixture.cs @@ -12,7 +12,8 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.TestDatabase.Containe /// Runs the PostgreSQL server the PostgreSQL integration tests use in a Docker container. /// internal sealed class PostgreSqlContainerFixture() - : DbContainerFixture(TestDatabaseDiagnosticMessageSink.Instance), ITestDatabaseContainerFixture + : DbContainerFixture(TestDatabaseDiagnosticMessageSink.Instance), + ITestDatabaseContainerFixture { /// public override string ConnectionString => @@ -21,17 +22,15 @@ internal sealed class PostgreSqlContainerFixture() Host = this.Container.Hostname, Port = this.Container.GetMappedPublicPort(PostgreSqlBuilder.PostgreSqlPort), Username = PostgreSqlBuilder.DefaultUsername, - Password = TestDatabaseContainers.Password + Password = TestDatabaseContainers.Password, }.ConnectionString; /// - public override DbProviderFactory DbProviderFactory => - NpgsqlFactory.Instance; + public override DbProviderFactory DbProviderFactory => NpgsqlFactory.Instance; /// protected override PostgreSqlBuilder Configure() => - new PostgreSqlBuilder(Image) - .WithPassword(TestDatabaseContainers.Password); + new PostgreSqlBuilder(Image).WithPassword(TestDatabaseContainers.Password); private const string Image = "postgres:latest"; } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/SqlServerContainerFixture.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/SqlServerContainerFixture.cs index 471dd5f..47f54a8 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/SqlServerContainerFixture.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/SqlServerContainerFixture.cs @@ -11,7 +11,8 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.TestDatabase.Containe /// Runs the SQL Server server the SQL Server integration tests use in a Docker container. /// internal sealed class SqlServerContainerFixture() - : DbContainerFixture(TestDatabaseDiagnosticMessageSink.Instance), ITestDatabaseContainerFixture + : DbContainerFixture(TestDatabaseDiagnosticMessageSink.Instance), + ITestDatabaseContainerFixture { /// public override string ConnectionString => @@ -26,17 +27,15 @@ internal sealed class SqlServerContainerFixture() Encrypt = false, // Several tests execute a command while a data reader is still open. - MultipleActiveResultSets = true + MultipleActiveResultSets = true, }.ConnectionString; /// - public override DbProviderFactory DbProviderFactory => - SqlClientFactory.Instance; + public override DbProviderFactory DbProviderFactory => SqlClientFactory.Instance; /// protected override MsSqlBuilder Configure() => - new MsSqlBuilder(Image) - .WithPassword(TestDatabaseContainers.Password); + new MsSqlBuilder(Image).WithPassword(TestDatabaseContainers.Password); private const string Image = "mcr.microsoft.com/mssql/server:2022-latest"; } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainer.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainer.cs index 438ce07..8011ada 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainer.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainer.cs @@ -28,8 +28,8 @@ internal sealed class TestDatabaseContainer(string databaseSystemName) ? this.fixture.Value.GetAwaiter().GetResult() : throw new InvalidOperationException( $"The {databaseSystemName} container has not been started. Tests reach a database through " - + $"{nameof(IntegrationTestsBase<>)}, which starts the container it needs before the first test " - + "of a test class runs." + + $"{nameof(IntegrationTestsBase<>)}, which starts the container it needs before the first test " + + "of a test class runs." ); /// @@ -54,8 +54,7 @@ public async ValueTask DisposeAsync() /// Starts the container and waits until the database server inside it accepts connections. Does nothing if the /// container is already starting or started. /// - public ValueTask StartAsync() => - new(this.fixture.Value); + public ValueTask StartAsync() => new(this.fixture.Value); private static async Task CreateAndStartAsync(string databaseSystemName) { @@ -75,7 +74,7 @@ private static async Task CreateAndStartAsync(string databaseSystemNam TestContext.Current.SendDiagnosticMessage( $"The {databaseSystemName} container is ready after {elapsedSeconds} seconds and is using the " - + $"following connection string: {connectionString}" + + $"following connection string: {connectionString}" ); return fixture; diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainerCleanup.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainerCleanup.cs index cb921e4..5e999dd 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainerCleanup.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainerCleanup.cs @@ -14,10 +14,8 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.TestDatabase.Containe public sealed class TestDatabaseContainerCleanup : IAsyncLifetime { /// - public ValueTask DisposeAsync() => - TestDatabaseContainers.DisposeAsync(); + public ValueTask DisposeAsync() => TestDatabaseContainers.DisposeAsync(); /// - public ValueTask InitializeAsync() => - default; + public ValueTask InitializeAsync() => default; } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainers.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainers.cs index c38d66c..50d6c05 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainers.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainers.cs @@ -22,26 +22,22 @@ internal static class TestDatabaseContainers /// /// The container running the MySQL server. /// - public static MySqlContainerFixture MySql => - mySql.Fixture; + public static MySqlContainerFixture MySql => mySql.Fixture; /// /// The container running the Oracle server. /// - public static OracleContainerFixture Oracle => - oracle.Fixture; + public static OracleContainerFixture Oracle => oracle.Fixture; /// /// The container running the PostgreSQL server. /// - public static PostgreSqlContainerFixture PostgreSql => - postgreSql.Fixture; + public static PostgreSqlContainerFixture PostgreSql => postgreSql.Fixture; /// /// The container running the SQL Server server. /// - public static SqlServerContainerFixture SqlServer => - sqlServer.Fixture; + public static SqlServerContainerFixture SqlServer => sqlServer.Fixture; /// /// Stops and removes every container that was started during the test run. @@ -57,26 +53,22 @@ public static async ValueTask DisposeAsync() /// /// Starts the MySQL container and waits until it accepts connections. /// - public static ValueTask StartMySqlAsync() => - mySql.StartAsync(); + public static ValueTask StartMySqlAsync() => mySql.StartAsync(); /// /// Starts the Oracle container and waits until it accepts connections. /// - public static ValueTask StartOracleAsync() => - oracle.StartAsync(); + public static ValueTask StartOracleAsync() => oracle.StartAsync(); /// /// Starts the PostgreSQL container and waits until it accepts connections. /// - public static ValueTask StartPostgreSqlAsync() => - postgreSql.StartAsync(); + public static ValueTask StartPostgreSqlAsync() => postgreSql.StartAsync(); /// /// Starts the SQL Server container and waits until it accepts connections. /// - public static ValueTask StartSqlServerAsync() => - sqlServer.StartAsync(); + public static ValueTask StartSqlServerAsync() => sqlServer.StartAsync(); private static readonly TestDatabaseContainer mySql = new("MySQL"); diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/MySqlTestDatabaseProvider.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/MySqlTestDatabaseProvider.cs index cbcc1d3..51dace2 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/MySqlTestDatabaseProvider.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/MySqlTestDatabaseProvider.cs @@ -84,8 +84,7 @@ public string GetCollationOfTemporaryTableColumn( string temporaryTableName, string columnName, DbConnection connection - ) => - throw new NotImplementedException(); + ) => throw new NotImplementedException(); /// public string GetDataTypeOfTemporaryTableColumn( @@ -93,14 +92,16 @@ public string GetDataTypeOfTemporaryTableColumn( string columnName, DbConnection connection ) => - connection.Query<(string Field, string Type, string Null, string Key, object Default, object Extra)>( - $"SHOW COLUMNS FROM `{temporaryTableName}` WHERE Field = '{columnName}'", - cancellationToken: TestContext.Current.CancellationToken - ).Select(a => a.Type.ToUpper()).First(); + connection + .Query<(string Field, string Type, string Null, string Key, object Default, object Extra)>( + $"SHOW COLUMNS FROM `{temporaryTableName}` WHERE Field = '{columnName}'", + cancellationToken: TestContext.Current.CancellationToken + ) + .Select(a => a.Type.ToUpper()) + .First(); /// - public string GetUnsupportedDataTypeLiteral() => - throw new NotImplementedException(); + public string GetUnsupportedDataTypeLiteral() => throw new NotImplementedException(); /// public void ResetDatabase() @@ -125,14 +126,12 @@ public void ResetDatabase() } /// - public static ValueTask StartDatabaseAsync() => - TestDatabaseContainers.StartMySqlAsync(); + public static ValueTask StartDatabaseAsync() => TestDatabaseContainers.StartMySqlAsync(); /// /// The connection string that connects to the MySQL server running in the test container. /// - private static string ConnectionString => - TestDatabaseContainers.MySql.ConnectionString; + private static string ConnectionString => TestDatabaseContainers.MySql.ConnectionString; private static void ExecuteScript(MySqlConnection connection, string script) { @@ -146,8 +145,7 @@ private static void ExecuteScript(MySqlConnection connection, string script) } } - private const string CreateDatabaseObjectsSql = - """ + private const string CreateDatabaseObjectsSql = """ CREATE TABLE `Entity` ( `Id` BIGINT, @@ -254,8 +252,7 @@ FOR EACH ROW private const string DatabaseName = "DbConnectionPlusTests"; - private const string PurgeTablesSql = - """ + private const string PurgeTablesSql = """ TRUNCATE TABLE `Entity`; GO diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/OracleTestDatabaseProvider.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/OracleTestDatabaseProvider.cs index 3af4ff3..f43ff6d 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/OracleTestDatabaseProvider.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/OracleTestDatabaseProvider.cs @@ -73,20 +73,17 @@ public string GetCollationOfTemporaryTableColumn( string temporaryTableName, string columnName, DbConnection connection - ) => - throw new NotImplementedException(); + ) => throw new NotImplementedException(); /// public string GetDataTypeOfTemporaryTableColumn( string temporaryTableName, string columnName, DbConnection connection - ) => - throw new NotImplementedException(); + ) => throw new NotImplementedException(); /// - public string GetUnsupportedDataTypeLiteral() => - throw new NotImplementedException(); + public string GetUnsupportedDataTypeLiteral() => throw new NotImplementedException(); /// public void ResetDatabase() @@ -106,14 +103,12 @@ public void ResetDatabase() } /// - public static ValueTask StartDatabaseAsync() => - TestDatabaseContainers.StartOracleAsync(); + public static ValueTask StartDatabaseAsync() => TestDatabaseContainers.StartOracleAsync(); /// /// The connection string that connects to the Oracle server running in the test container. /// - private static string ConnectionString => - TestDatabaseContainers.Oracle.ConnectionString; + private static string ConnectionString => TestDatabaseContainers.Oracle.ConnectionString; private static void ExecuteScript(OracleConnection connection, string script) { @@ -127,8 +122,7 @@ private static void ExecuteScript(OracleConnection connection, string script) } } - private const string CreateDatabaseObjectsSql = - """ + private const string CreateDatabaseObjectsSql = """ CREATE TABLE "Entity" ( "Id" NUMBER(19) NOT NULL PRIMARY KEY, @@ -204,8 +198,7 @@ CREATE OR REPLACE NONEDITIONABLE PROCEDURE "DeleteAllEntities" AS """; - private const string DropDatabaseObjectsSql = - """ + private const string DropDatabaseObjectsSql = """ DROP TABLE IF EXISTS "Entity" PURGE; GO @@ -225,8 +218,7 @@ CREATE OR REPLACE NONEDITIONABLE PROCEDURE "DeleteAllEntities" AS GO """; - private const string PurgeTablesSql = - """ + private const string PurgeTablesSql = """ TRUNCATE TABLE "Entity"; GO diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/PostgreSqlTestDatabaseProvider.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/PostgreSqlTestDatabaseProvider.cs index c18e4c8..7a082b8 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/PostgreSqlTestDatabaseProvider.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/PostgreSqlTestDatabaseProvider.cs @@ -57,11 +57,11 @@ public DbConnection CreateConnection() public bool ExistsTemporaryTable(string tableName, DbConnection connection, DbTransaction? transaction = null) => connection.Exists( $""" - SELECT 1 - FROM information_schema.tables - WHERE table_type = 'LOCAL TEMPORARY' AND - table_name = '{tableName}' - """, + SELECT 1 + FROM information_schema.tables + WHERE table_type = 'LOCAL TEMPORARY' AND + table_name = '{tableName}' + """, transaction, cancellationToken: TestContext.Current.CancellationToken ); @@ -71,8 +71,7 @@ public string GetCollationOfTemporaryTableColumn( string temporaryTableName, string columnName, DbConnection connection - ) => - throw new NotImplementedException(); + ) => throw new NotImplementedException(); /// public string GetDataTypeOfTemporaryTableColumn( @@ -82,18 +81,17 @@ DbConnection connection ) => connection.QuerySingle( $""" - SELECT data_type - FROM information_schema.columns - WHERE table_schema LIKE 'pg_temp%' AND - table_name = '{temporaryTableName}' AND - column_name = '{columnName}' - """, + SELECT data_type + FROM information_schema.columns + WHERE table_schema LIKE 'pg_temp%' AND + table_name = '{temporaryTableName}' AND + column_name = '{columnName}' + """, cancellationToken: TestContext.Current.CancellationToken ); /// - public string GetUnsupportedDataTypeLiteral() => - "(1, 2)"; + public string GetUnsupportedDataTypeLiteral() => "(1, 2)"; public void ResetDatabase() { @@ -117,17 +115,14 @@ public void ResetDatabase() } /// - public static ValueTask StartDatabaseAsync() => - TestDatabaseContainers.StartPostgreSqlAsync(); + public static ValueTask StartDatabaseAsync() => TestDatabaseContainers.StartPostgreSqlAsync(); /// /// The connection string that connects to the PostgreSQL server running in the test container. /// - private static string ConnectionString => - TestDatabaseContainers.PostgreSql.ConnectionString; + private static string ConnectionString => TestDatabaseContainers.PostgreSql.ConnectionString; - private const string CreateDatabaseObjectsSql = - """ + private const string CreateDatabaseObjectsSql = """ CREATE EXTENSION IF NOT EXISTS pgcrypto; -- Needed for gen_random_bytes() CREATE TABLE "Entity" @@ -230,8 +225,7 @@ DELETE FROM "Entity" private const string DatabaseName = "DbConnectionPlusTests"; - private const string PurgeTablesSql = - """ + private const string PurgeTablesSql = """ TRUNCATE TABLE "Entity"; TRUNCATE TABLE "EntityWithEnumStoredAsString"; TRUNCATE TABLE "EntityWithEnumStoredAsInteger"; diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SQLiteTestDatabaseProvider.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SQLiteTestDatabaseProvider.cs index 80b8cb3..7b70210 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SQLiteTestDatabaseProvider.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SQLiteTestDatabaseProvider.cs @@ -33,13 +33,13 @@ public SqliteTestDatabaseProvider() /// public string DelayTwoSecondsStatement => """ - WITH RECURSIVE delay(x) AS ( - SELECT 1 - UNION ALL - SELECT x + 1 FROM delay WHERE x < 5000000 - ) - SELECT x FROM delay WHERE x = 5000000; - """; + WITH RECURSIVE delay(x) AS ( + SELECT 1 + UNION ALL + SELECT x + 1 FROM delay WHERE x < 5000000 + ) + SELECT x FROM delay WHERE x = 5000000; + """; /// public bool HasUnsupportedDataType => false; @@ -63,18 +63,17 @@ SELECT x + 1 FROM delay WHERE x < 5000000 public bool TemporaryTableTextColumnInheritsCollationFromDatabase => true; /// - public DbConnection CreateConnection() => - this.connection; + public DbConnection CreateConnection() => this.connection; /// public bool ExistsTemporaryTable(string tableName, DbConnection connection, DbTransaction? transaction = null) => this.connection.Exists( $""" - SELECT 1 - FROM sqlite_temp_master - WHERE type = 'table' - AND name = '{tableName}' - """, + SELECT 1 + FROM sqlite_temp_master + WHERE type = 'table' + AND name = '{tableName}' + """, transaction, cancellationToken: TestContext.Current.CancellationToken ); @@ -84,8 +83,7 @@ public string GetCollationOfTemporaryTableColumn( string temporaryTableName, string columnName, DbConnection connection - ) => - throw new NotImplementedException(); + ) => throw new NotImplementedException(); /// public string GetDataTypeOfTemporaryTableColumn( @@ -93,11 +91,11 @@ public string GetDataTypeOfTemporaryTableColumn( string columnName, DbConnection connection ) => - this.connection - .Query<(int cid, string name, string Type, bool notnull, object dflt_value, int pk)>( + this + .connection.Query<(int cid, string name, string Type, bool notnull, object dflt_value, int pk)>( $""" - PRAGMA table_info("{temporaryTableName}"); - """, + PRAGMA table_info("{temporaryTableName}"); + """, cancellationToken: TestContext.Current.CancellationToken ) .Where(a => a.name == columnName) @@ -105,8 +103,7 @@ DbConnection connection .Single(); /// - public string GetUnsupportedDataTypeLiteral() => - throw new NotImplementedException(); + public string GetUnsupportedDataTypeLiteral() => throw new NotImplementedException(); /// public void ResetDatabase() @@ -121,15 +118,13 @@ public void ResetDatabase() /// /// SQLite runs in-process, in memory, so there is no server and nothing to start. - public static ValueTask StartDatabaseAsync() => - default; + public static ValueTask StartDatabaseAsync() => default; private readonly SqliteConnection connection; private bool isDatabasePrepared; - private const string CreateDatabaseObjectsSql = - """ + private const string CreateDatabaseObjectsSql = """ CREATE TABLE Entity ( Id INTEGER, diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SqlServerTestDatabaseProvider.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SqlServerTestDatabaseProvider.cs index db62ed9..4e8b21c 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SqlServerTestDatabaseProvider.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SqlServerTestDatabaseProvider.cs @@ -70,10 +70,10 @@ DbConnection connection ) => connection.ExecuteScalar( $""" - SELECT C.collation_name AS CollationName - FROM tempdb.sys.columns C - WHERE c.object_id = OBJECT_ID('tempdb..#{temporaryTableName}') AND C.name = '{columnName}' - """, + SELECT C.collation_name AS CollationName + FROM tempdb.sys.columns C + WHERE c.object_id = OBJECT_ID('tempdb..#{temporaryTableName}') AND C.name = '{columnName}' + """, cancellationToken: TestContext.Current.CancellationToken ); @@ -85,17 +85,16 @@ DbConnection connection ) => connection.QuerySingle( $""" - SELECT t.name AS DataType - FROM tempdb.sys.columns c - JOIN tempdb.sys.types t ON c.user_type_id = t.user_type_id - WHERE c.object_id = OBJECT_ID('tempdb..#{temporaryTableName}') AND c.name = '{columnName}' - """, + SELECT t.name AS DataType + FROM tempdb.sys.columns c + JOIN tempdb.sys.types t ON c.user_type_id = t.user_type_id + WHERE c.object_id = OBJECT_ID('tempdb..#{temporaryTableName}') AND c.name = '{columnName}' + """, cancellationToken: TestContext.Current.CancellationToken ); /// - public string GetUnsupportedDataTypeLiteral() => - "CONVERT(SQL_VARIANT, 123)"; + public string GetUnsupportedDataTypeLiteral() => "CONVERT(SQL_VARIANT, 123)"; /// public void ResetDatabase() @@ -107,12 +106,12 @@ public void ResetDatabase() { connection.ExecuteNonQuery( $""" - IF EXISTS (SELECT name FROM sys.databases WHERE name = N'{DatabaseName}') - BEGIN - ALTER DATABASE [{DatabaseName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; - DROP DATABASE [{DatabaseName}]; - END - """ + IF EXISTS (SELECT name FROM sys.databases WHERE name = N'{DatabaseName}') + BEGIN + ALTER DATABASE [{DatabaseName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; + DROP DATABASE [{DatabaseName}]; + END + """ ); connection.ExecuteNonQuery($"CREATE DATABASE [{DatabaseName}] COLLATE {this.DatabaseCollation}"); @@ -130,14 +129,12 @@ IF EXISTS (SELECT name FROM sys.databases WHERE name = N'{DatabaseName}') } /// - public static ValueTask StartDatabaseAsync() => - TestDatabaseContainers.StartSqlServerAsync(); + public static ValueTask StartDatabaseAsync() => TestDatabaseContainers.StartSqlServerAsync(); /// /// The connection string that connects to the SQL Server server running in the test container. /// - private static string ConnectionString => - TestDatabaseContainers.SqlServer.ConnectionString; + private static string ConnectionString => TestDatabaseContainers.SqlServer.ConnectionString; private static void ExecuteScript(SqlConnection connection, string script) { @@ -151,8 +148,7 @@ private static void ExecuteScript(SqlConnection connection, string script) } } - private const string CreateDatabaseObjectsSql = - """ + private const string CreateDatabaseObjectsSql = """ CREATE TABLE Entity ( Id BIGINT NOT NULL PRIMARY KEY, @@ -257,8 +253,7 @@ DELETE FROM Entity private const string DatabaseName = "DbConnectionPlusTests"; - private const string PurgeTablesSql = - """ + private const string PurgeTablesSql = """ TRUNCATE TABLE Entity; GO diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/TestDatabaseFixture.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/TestDatabaseFixture.cs index e90e677..2d76054 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/TestDatabaseFixture.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/TestDatabaseFixture.cs @@ -23,10 +23,8 @@ public sealed class TestDatabaseFixture : IAsyncLifetime where TTestDatabaseProvider : ITestDatabaseProvider, new() { /// - public ValueTask DisposeAsync() => - default; + public ValueTask DisposeAsync() => default; /// - public ValueTask InitializeAsync() => - TTestDatabaseProvider.StartDatabaseAsync(); + public ValueTask InitializeAsync() => TTestDatabaseProvider.StartDatabaseAsync(); } diff --git a/tests/DbConnectionPlus.UnitTests/Assertions/AssertionsExtensions.cs b/tests/DbConnectionPlus.UnitTests/Assertions/AssertionsExtensions.cs index 55301d7..5362115 100644 --- a/tests/DbConnectionPlus.UnitTests/Assertions/AssertionsExtensions.cs +++ b/tests/DbConnectionPlus.UnitTests/Assertions/AssertionsExtensions.cs @@ -16,7 +16,8 @@ public static class AssertionsExtensions /// The expected types of which the subject should be one. [CustomAssertion] public static void BeAnyOf(this TypeAssertions assertions, params Type[] expectations) => - AssertionChain.GetOrCreate() + AssertionChain + .GetOrCreate() .ForCondition(expectations.Contains(assertions.Subject)) .FailWith("Expected {context} to be any of {0}, but found {1}", expectations, assertions.Subject); } diff --git a/tests/DbConnectionPlus.UnitTests/Assertions/DecoratorAssertions.cs b/tests/DbConnectionPlus.UnitTests/Assertions/DecoratorAssertions.cs index 7a98f2f..311884d 100644 --- a/tests/DbConnectionPlus.UnitTests/Assertions/DecoratorAssertions.cs +++ b/tests/DbConnectionPlus.UnitTests/Assertions/DecoratorAssertions.cs @@ -81,8 +81,7 @@ HashSet excludedMethods if (method.ReturnType != typeof(void)) { // Make sure the decorator method returned the same value as the decorated method: - decoratorMethodReturnValue - .Should().Be(decoratedMethodReturnValue); + decoratorMethodReturnValue.Should().Be(decoratedMethodReturnValue); } // Make sure the decorated method was called with the same arguments as the decorator method: @@ -97,13 +96,13 @@ HashSet excludedMethods throw new( $""" - The forward call assertion failed for the following method: - Type: {decoratorType.FullName} - Method: {method} + The forward call assertion failed for the following method: + Type: {decoratorType.FullName} + Method: {method} - Failure: - {ex} - """ + Failure: + {ex} + """ ); } } @@ -112,10 +111,9 @@ HashSet excludedMethods /// /// The method. /// - private static readonly MethodInfo specimenFactoryCreateMethod = typeof(SpecimenFactory) - .GetMethod( - nameof(SpecimenFactory.Create), - BindingFlags.Public | BindingFlags.Static, - [typeof(ISpecimenBuilder)] - )!; + private static readonly MethodInfo specimenFactoryCreateMethod = typeof(SpecimenFactory).GetMethod( + nameof(SpecimenFactory.Create), + BindingFlags.Public | BindingFlags.Static, + [typeof(ISpecimenBuilder)] + )!; } diff --git a/tests/DbConnectionPlus.UnitTests/Configuration/DbConnectionPlusConfigurationTests.cs b/tests/DbConnectionPlus.UnitTests/Configuration/DbConnectionPlusConfigurationTests.cs index 36730b3..a787161 100644 --- a/tests/DbConnectionPlus.UnitTests/Configuration/DbConnectionPlusConfigurationTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Configuration/DbConnectionPlusConfigurationTests.cs @@ -21,18 +21,16 @@ public void EnumSerializationMode_Integers_ShouldSerializeEnumAsInteger() DbParameter? interceptedDbParameter = null; - DbConnectionPlusConfiguration.Instance.InterceptDbCommand = - (command, _) => interceptedDbParameter = command.Parameters[0]; + DbConnectionPlusConfiguration.Instance.InterceptDbCommand = (command, _) => + interceptedDbParameter = command.Parameters[0]; DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Integers; this.MockDbConnection.ExecuteNonQuery($"SELECT {Parameter(enumValue)}"); - interceptedDbParameter - .Should().NotBeNull(); + interceptedDbParameter.Should().NotBeNull(); - interceptedDbParameter.Value - .Should().Be((int)enumValue); + interceptedDbParameter.Value.Should().Be((int)enumValue); } [Fact] @@ -42,18 +40,16 @@ public void EnumSerializationMode_Strings_ShouldSerializeEnumAsString() DbParameter? interceptedDbParameter = null; - DbConnectionPlusConfiguration.Instance.InterceptDbCommand = - (command, _) => interceptedDbParameter = command.Parameters[0]; + DbConnectionPlusConfiguration.Instance.InterceptDbCommand = (command, _) => + interceptedDbParameter = command.Parameters[0]; DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Strings; this.MockDbConnection.ExecuteNonQuery($"SELECT {Parameter(enumValue)}"); - interceptedDbParameter - .Should().NotBeNull(); + interceptedDbParameter.Should().NotBeNull(); - interceptedDbParameter.Value - .Should().Be(enumValue.ToString()); + interceptedDbParameter.Value.Should().Be(enumValue.ToString()); } [Fact] @@ -72,40 +68,47 @@ public void Freeze_ShouldFreezeConfigurationAndEntityTypeBuilders() ((IFreezable)configuration).Freeze(); Invoking(() => configuration.EnumSerializationMode = EnumSerializationMode.Integers) - .Should().Throw() + .Should() + .Throw() .WithMessage("The configuration of DbConnectionPlus is frozen and can no longer be modified."); Invoking(() => configuration.InterceptDbCommand = null) - .Should().Throw() + .Should() + .Throw() .WithMessage("The configuration of DbConnectionPlus is frozen and can no longer be modified."); Invoking(() => configuration.Entity()) - .Should().Throw() + .Should() + .Throw() .WithMessage("The configuration of DbConnectionPlus is frozen and can no longer be modified."); Invoking(() => entityTypeBuilder.ToTable("Entities")) - .Should().Throw() + .Should() + .Throw() .WithMessage("The configuration of DbConnectionPlus is frozen and can no longer be modified."); Invoking(() => entityTypeBuilder.Property(a => a.Id)) - .Should().Throw() + .Should() + .Throw() .WithMessage("The configuration of DbConnectionPlus is frozen and can no longer be modified."); Invoking(() => entityPropertyBuilder.IsKey()) - .Should().Throw() + .Should() + .Throw() .WithMessage("The configuration of DbConnectionPlus is frozen and can no longer be modified."); } [Fact] public void GetDatabaseAdapter_NoAdapterRegisteredForConnectionType_ShouldThrow() => Invoking(() => DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(typeof(FakeConnectionC))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "No database adapter is registered for the database connection of the type " + - $"{typeof(FakeConnectionC)}. Please install the corresponding adapter NuGet package " + - "(e.g., RentADeveloper.DbConnectionPlus.DatabaseAdapters.SqlServer) " + - "and register it by calling the appropriate UseXxx() extension method via " + - $"{nameof(DbConnectionExtensions)}.{nameof(DbConnectionExtensions.Configure)}." + "No database adapter is registered for the database connection of the type " + + $"{typeof(FakeConnectionC)}. Please install the corresponding adapter NuGet package " + + "(e.g., RentADeveloper.DbConnectionPlus.DatabaseAdapters.SqlServer) " + + "and register it by calling the appropriate UseXxx() extension method via " + + $"{nameof(DbConnectionExtensions)}.{nameof(DbConnectionExtensions.Configure)}." ); [Fact] @@ -117,11 +120,9 @@ public void GetDatabaseAdapter_ShouldGetAdapter() DbConnectionPlusConfiguration.Instance.RegisterDatabaseAdapter(adapterA); DbConnectionPlusConfiguration.Instance.RegisterDatabaseAdapter(adapterB); - DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(typeof(FakeConnectionA)) - .Should().BeSameAs(adapterA); + DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(typeof(FakeConnectionA)).Should().BeSameAs(adapterA); - DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(typeof(FakeConnectionB)) - .Should().BeSameAs(adapterB); + DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(typeof(FakeConnectionB)).Should().BeSameAs(adapterB); } [Fact] @@ -133,20 +134,30 @@ public void GetDatabaseAdapter_ShouldGetRegisteredAdapters() DbConnectionPlusConfiguration.Instance.UseSqlite(); DbConnectionPlusConfiguration.Instance.UseSqlServer(); - DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(typeof(MySqlConnection)) - .Should().BeOfType(); - - DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(typeof(OracleConnection)) - .Should().BeOfType(); - - DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(typeof(NpgsqlConnection)) - .Should().BeOfType(); - - DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(typeof(SqliteConnection)) - .Should().BeOfType(); - - DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(typeof(SqlConnection)) - .Should().BeOfType(); + DbConnectionPlusConfiguration + .Instance.GetDatabaseAdapter(typeof(MySqlConnection)) + .Should() + .BeOfType(); + + DbConnectionPlusConfiguration + .Instance.GetDatabaseAdapter(typeof(OracleConnection)) + .Should() + .BeOfType(); + + DbConnectionPlusConfiguration + .Instance.GetDatabaseAdapter(typeof(NpgsqlConnection)) + .Should() + .BeOfType(); + + DbConnectionPlusConfiguration + .Instance.GetDatabaseAdapter(typeof(SqliteConnection)) + .Should() + .BeOfType(); + + DbConnectionPlusConfiguration + .Instance.GetDatabaseAdapter(typeof(SqlConnection)) + .Should() + .BeOfType(); } [Fact] @@ -159,17 +170,11 @@ public void GetEntityTypeBuilders_ShouldGetConfiguredBuilders() var entityTypeBuilders = configuration.GetEntityTypeBuilders(); - entityTypeBuilders - .Should().ContainKeys( - typeof(Entity), - typeof(MappingTestEntityFluentApi) - ); + entityTypeBuilders.Should().ContainKeys(typeof(Entity), typeof(MappingTestEntityFluentApi)); - entityTypeBuilders[typeof(Entity)] - .Should().BeSameAs(entityBuilder); + entityTypeBuilders[typeof(Entity)].Should().BeSameAs(entityBuilder); - entityTypeBuilders[typeof(MappingTestEntityFluentApi)] - .Should().BeSameAs(mappingTestEntityFluentApiBuilder); + entityTypeBuilders[typeof(MappingTestEntityFluentApi)].Should().BeSameAs(mappingTestEntityFluentApiBuilder); } [Fact] @@ -182,17 +187,13 @@ public void InterceptDbCommand_ShouldInterceptDbCommands() interceptor .WhenForAnyArgs(interceptor2 => - interceptor2.Invoke( - Arg.Any(), - Arg.Any>() - ) + interceptor2.Invoke(Arg.Any(), Arg.Any>()) ) .Do(info => - { - interceptedDbCommand = info.Arg(); - interceptedTemporaryTables = info.Arg>(); - } - ); + { + interceptedDbCommand = info.Arg(); + interceptedTemporaryTables = info.Arg>(); + }); DbConnectionPlusConfiguration.Instance.InterceptDbCommand = interceptor; @@ -200,12 +201,11 @@ public void InterceptDbCommand_ShouldInterceptDbCommands() var entityIds = Generate.Ids(); var stringValue = entities[0].StringValue; - InterpolatedSqlStatement statement = - $""" - SELECT Id, StringValue - FROM {TemporaryTable(entities)} TEntity - WHERE TEntity.Id IN ({TemporaryTable(entityIds)}) OR StringValue = {Parameter(stringValue)} - """; + InterpolatedSqlStatement statement = $""" + SELECT Id, StringValue + FROM {TemporaryTable(entities)} TEntity + WHERE TEntity.Id IN ({TemporaryTable(entityIds)}) OR StringValue = {Parameter(stringValue)} + """; var temporaryTables = statement.TemporaryTables; @@ -213,54 +213,45 @@ WHERE TEntity.Id IN ({TemporaryTable(entityIds)}) OR StringValue = {Parameter(s var timeout = Generate.Single(); var cancellationToken = Generate.Single(); - _ = this.MockDbConnection.Query( - statement, - transaction, - timeout, - CommandType.StoredProcedure, - cancellationToken - ).ToList(); - - interceptor.Received().Invoke( - Arg.Any(), - Arg.Any>() - ); + _ = this + .MockDbConnection.Query( + statement, + transaction, + timeout, + CommandType.StoredProcedure, + cancellationToken + ) + .ToList(); - interceptedDbCommand - .Should().NotBeNull(); + interceptor.Received().Invoke(Arg.Any(), Arg.Any>()); - interceptedDbCommand.CommandText - .Should().Be( + interceptedDbCommand.Should().NotBeNull(); + + interceptedDbCommand + .CommandText.Should() + .Be( $""" - SELECT Id, StringValue - FROM [#{temporaryTables[0].Name}] TEntity - WHERE TEntity.Id IN ([#{temporaryTables[1].Name}]) OR StringValue = @StringValue - """ + SELECT Id, StringValue + FROM [#{temporaryTables[0].Name}] TEntity + WHERE TEntity.Id IN ([#{temporaryTables[1].Name}]) OR StringValue = @StringValue + """ ); - interceptedDbCommand.Transaction - .Should().Be(transaction); + interceptedDbCommand.Transaction.Should().Be(transaction); - interceptedDbCommand.CommandType - .Should().Be(CommandType.StoredProcedure); + interceptedDbCommand.CommandType.Should().Be(CommandType.StoredProcedure); - interceptedDbCommand.CommandTimeout - .Should().Be((int)timeout.TotalSeconds); + interceptedDbCommand.CommandTimeout.Should().Be((int)timeout.TotalSeconds); - interceptedDbCommand.Parameters.Count - .Should().Be(1); + interceptedDbCommand.Parameters.Count.Should().Be(1); - interceptedDbCommand.Parameters[0].ParameterName - .Should().Be("StringValue"); + interceptedDbCommand.Parameters[0].ParameterName.Should().Be("StringValue"); - interceptedDbCommand.Parameters[0].Value - .Should().Be(stringValue); + interceptedDbCommand.Parameters[0].Value.Should().Be(stringValue); - interceptedTemporaryTables - .Should().NotBeNull(); + interceptedTemporaryTables.Should().NotBeNull(); - interceptedTemporaryTables - .Should().BeEquivalentTo(temporaryTables); + interceptedTemporaryTables.Should().BeEquivalentTo(temporaryTables); } [Fact] @@ -270,15 +261,13 @@ public void RegisterDatabaseAdapter_ShouldRegisterAdapter() DbConnectionPlusConfiguration.Instance.RegisterDatabaseAdapter(adapterA); - DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(typeof(FakeConnectionA)) - .Should().BeSameAs(adapterA); + DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(typeof(FakeConnectionA)).Should().BeSameAs(adapterA); var adapterB = Substitute.For(); DbConnectionPlusConfiguration.Instance.RegisterDatabaseAdapter(adapterB); - DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(typeof(FakeConnectionB)) - .Should().BeSameAs(adapterB); + DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(typeof(FakeConnectionB)).Should().BeSameAs(adapterB); } [Fact] @@ -288,15 +277,13 @@ public void RegisterDatabaseAdapter_ShouldReplaceRegisteredAdapter() DbConnectionPlusConfiguration.Instance.RegisterDatabaseAdapter(adapterA); - DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(typeof(FakeConnectionA)) - .Should().BeSameAs(adapterA); + DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(typeof(FakeConnectionA)).Should().BeSameAs(adapterA); var adapterB = Substitute.For(); DbConnectionPlusConfiguration.Instance.RegisterDatabaseAdapter(adapterB); - DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(typeof(FakeConnectionA)) - .Should().BeSameAs(adapterB); + DbConnectionPlusConfiguration.Instance.GetDatabaseAdapter(typeof(FakeConnectionA)).Should().BeSameAs(adapterB); } [Fact] diff --git a/tests/DbConnectionPlus.UnitTests/Configuration/EntityPropertyBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/Configuration/EntityPropertyBuilderTests.cs index ad2d6dc..16af487 100644 --- a/tests/DbConnectionPlus.UnitTests/Configuration/EntityPropertyBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Configuration/EntityPropertyBuilderTests.cs @@ -9,8 +9,7 @@ public void ColumnName_Configured_ShouldReturnColumnName() builder.HasColumnName("Identifier"); - ((IEntityPropertyBuilder)builder).ColumnName - .Should().Be("Identifier"); + ((IEntityPropertyBuilder)builder).ColumnName.Should().Be("Identifier"); } [Fact] @@ -18,8 +17,7 @@ public void ColumnName_NotConfigured_ShouldReturnNull() { var builder = new EntityPropertyBuilder(Substitute.For(), "Property"); - ((IEntityPropertyBuilder)builder).ColumnName - .Should().BeNull(); + ((IEntityPropertyBuilder)builder).ColumnName.Should().BeNull(); } [Fact] @@ -30,31 +28,38 @@ public void Freeze_ShouldFreezeBuilder() ((IFreezable)builder).Freeze(); Invoking(() => builder.HasColumnName("Identifier")) - .Should().Throw() + .Should() + .Throw() .WithMessage("The configuration of DbConnectionPlus is frozen and can no longer be modified."); Invoking(() => builder.IsComputed()) - .Should().Throw() + .Should() + .Throw() .WithMessage("The configuration of DbConnectionPlus is frozen and can no longer be modified."); Invoking(() => builder.IsConcurrencyToken()) - .Should().Throw() + .Should() + .Throw() .WithMessage("The configuration of DbConnectionPlus is frozen and can no longer be modified."); Invoking(() => builder.IsIdentity()) - .Should().Throw() + .Should() + .Throw() .WithMessage("The configuration of DbConnectionPlus is frozen and can no longer be modified."); Invoking(() => builder.IsIgnored()) - .Should().Throw() + .Should() + .Throw() .WithMessage("The configuration of DbConnectionPlus is frozen and can no longer be modified."); Invoking(() => builder.IsKey()) - .Should().Throw() + .Should() + .Throw() .WithMessage("The configuration of DbConnectionPlus is frozen and can no longer be modified."); Invoking(() => builder.IsRowVersion()) - .Should().Throw() + .Should() + .Throw() .WithMessage("The configuration of DbConnectionPlus is frozen and can no longer be modified."); } @@ -65,8 +70,7 @@ public void HasColumnName_ShouldSetColumnName() builder.HasColumnName("Identifier"); - ((IEntityPropertyBuilder)builder).ColumnName - .Should().Be("Identifier"); + ((IEntityPropertyBuilder)builder).ColumnName.Should().Be("Identifier"); } [Fact] @@ -76,8 +80,7 @@ public void IsComputed_Configured_ShouldReturnTrue() builder.IsComputed(); - ((IEntityPropertyBuilder)builder).IsComputed - .Should().BeTrue(); + ((IEntityPropertyBuilder)builder).IsComputed.Should().BeTrue(); } [Fact] @@ -85,8 +88,7 @@ public void IsComputed_NotConfigured_ShouldReturnFalse() { var builder = new EntityPropertyBuilder(Substitute.For(), "Property"); - ((IEntityPropertyBuilder)builder).IsComputed - .Should().BeFalse(); + ((IEntityPropertyBuilder)builder).IsComputed.Should().BeFalse(); } [Fact] @@ -96,8 +98,7 @@ public void IsComputed_ShouldMarkPropertyAsComputed() builder.IsComputed(); - ((IEntityPropertyBuilder)builder).IsComputed - .Should().BeTrue(); + ((IEntityPropertyBuilder)builder).IsComputed.Should().BeTrue(); } [Fact] @@ -107,8 +108,7 @@ public void IsConcurrencyToken_Configured_ShouldReturnTrue() builder.IsConcurrencyToken(); - ((IEntityPropertyBuilder)builder).IsConcurrencyToken - .Should().BeTrue(); + ((IEntityPropertyBuilder)builder).IsConcurrencyToken.Should().BeTrue(); } [Fact] @@ -116,8 +116,7 @@ public void IsConcurrencyToken_NotConfigured_ShouldReturnFalse() { var builder = new EntityPropertyBuilder(Substitute.For(), "Property"); - ((IEntityPropertyBuilder)builder).IsConcurrencyToken - .Should().BeFalse(); + ((IEntityPropertyBuilder)builder).IsConcurrencyToken.Should().BeFalse(); } [Fact] @@ -127,8 +126,7 @@ public void IsConcurrencyToken_ShouldMarkPropertyAsConcurrencyToken() builder.IsConcurrencyToken(); - ((IEntityPropertyBuilder)builder).IsConcurrencyToken - .Should().BeTrue(); + ((IEntityPropertyBuilder)builder).IsConcurrencyToken.Should().BeTrue(); } [Fact] @@ -138,8 +136,7 @@ public void IsIdentity_Configured_ShouldReturnTrue() builder.IsIdentity(); - ((IEntityPropertyBuilder)builder).IsIdentity - .Should().BeTrue(); + ((IEntityPropertyBuilder)builder).IsIdentity.Should().BeTrue(); } [Fact] @@ -147,8 +144,7 @@ public void IsIdentity_NotConfigured_ShouldReturnFalse() { var builder = new EntityPropertyBuilder(Substitute.For(), "Property"); - ((IEntityPropertyBuilder)builder).IsIdentity - .Should().BeFalse(); + ((IEntityPropertyBuilder)builder).IsIdentity.Should().BeFalse(); } [Fact] @@ -161,10 +157,11 @@ public void IsIdentity_OtherPropertyIsAlreadyMarked_ShouldThrow() var propertyBuilder = new EntityPropertyBuilder(entityTypeBuilder, "NotId"); Invoking(() => propertyBuilder.IsIdentity()) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "There is already the property 'Id' marked as an identity property for the entity type " + - $"{typeof(Entity)}. Only one property can be marked as identity property per entity type." + "There is already the property 'Id' marked as an identity property for the entity type " + + $"{typeof(Entity)}. Only one property can be marked as identity property per entity type." ); } @@ -175,8 +172,7 @@ public void IsIdentity_ShouldMarkPropertyAsIdentity() builder.IsIdentity(); - ((IEntityPropertyBuilder)builder).IsIdentity - .Should().BeTrue(); + ((IEntityPropertyBuilder)builder).IsIdentity.Should().BeTrue(); } [Fact] @@ -186,8 +182,7 @@ public void IsIgnored_Configured_ShouldReturnTrue() builder.IsIgnored(); - ((IEntityPropertyBuilder)builder).IsIgnored - .Should().BeTrue(); + ((IEntityPropertyBuilder)builder).IsIgnored.Should().BeTrue(); } [Fact] @@ -195,8 +190,7 @@ public void IsIgnored_NotConfigured_ShouldReturnFalse() { var builder = new EntityPropertyBuilder(Substitute.For(), "Property"); - ((IEntityPropertyBuilder)builder).IsIgnored - .Should().BeFalse(); + ((IEntityPropertyBuilder)builder).IsIgnored.Should().BeFalse(); } [Fact] @@ -206,8 +200,7 @@ public void IsIgnored_ShouldMarkPropertyAsIgnored() builder.IsIgnored(); - ((IEntityPropertyBuilder)builder).IsIgnored - .Should().BeTrue(); + ((IEntityPropertyBuilder)builder).IsIgnored.Should().BeTrue(); } [Fact] @@ -217,8 +210,7 @@ public void IsKey_Configured_ShouldReturnTrue() builder.IsKey(); - ((IEntityPropertyBuilder)builder).IsKey - .Should().BeTrue(); + ((IEntityPropertyBuilder)builder).IsKey.Should().BeTrue(); } [Fact] @@ -226,8 +218,7 @@ public void IsKey_NotConfigured_ShouldReturnFalse() { var builder = new EntityPropertyBuilder(Substitute.For(), "Property"); - ((IEntityPropertyBuilder)builder).IsKey - .Should().BeFalse(); + ((IEntityPropertyBuilder)builder).IsKey.Should().BeFalse(); } [Fact] @@ -237,8 +228,7 @@ public void IsKey_ShouldMarkPropertyAsKey() builder.IsKey(); - ((IEntityPropertyBuilder)builder).IsKey - .Should().BeTrue(); + ((IEntityPropertyBuilder)builder).IsKey.Should().BeTrue(); } [Fact] @@ -248,8 +238,7 @@ public void IsRowVersion_Configured_ShouldReturnTrue() builder.IsRowVersion(); - ((IEntityPropertyBuilder)builder).IsRowVersion - .Should().BeTrue(); + ((IEntityPropertyBuilder)builder).IsRowVersion.Should().BeTrue(); } [Fact] @@ -257,8 +246,7 @@ public void IsRowVersion_NotConfigured_ShouldReturnFalse() { var builder = new EntityPropertyBuilder(Substitute.For(), "Property"); - ((IEntityPropertyBuilder)builder).IsRowVersion - .Should().BeFalse(); + ((IEntityPropertyBuilder)builder).IsRowVersion.Should().BeFalse(); } [Fact] @@ -268,8 +256,7 @@ public void IsRowVersion_ShouldMarkPropertyAsRowVersion() builder.IsRowVersion(); - ((IEntityPropertyBuilder)builder).IsRowVersion - .Should().BeTrue(); + ((IEntityPropertyBuilder)builder).IsRowVersion.Should().BeTrue(); } [Fact] @@ -277,8 +264,7 @@ public void PropertyName_ShouldReturnPropertyName() { var builder = new EntityPropertyBuilder(Substitute.For(), "Property"); - ((IEntityPropertyBuilder)builder).PropertyName - .Should().Be("Property"); + ((IEntityPropertyBuilder)builder).PropertyName.Should().Be("Property"); } [Fact] diff --git a/tests/DbConnectionPlus.UnitTests/Configuration/EntityTypeBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/Configuration/EntityTypeBuilderTests.cs index 77c08ff..2049a98 100644 --- a/tests/DbConnectionPlus.UnitTests/Configuration/EntityTypeBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Configuration/EntityTypeBuilderTests.cs @@ -14,15 +14,18 @@ public void Freeze_ShouldFreezeBuilderAndAllPropertyBuilders() ((IFreezable)builder).Freeze(); Invoking(() => builder.ToTable("Entities2")) - .Should().Throw() + .Should() + .Throw() .WithMessage("The configuration of DbConnectionPlus is frozen and can no longer be modified."); Invoking(() => builder.Property(a => a.Id).HasColumnName("Identifier")) - .Should().Throw() + .Should() + .Throw() .WithMessage("The configuration of DbConnectionPlus is frozen and can no longer be modified."); Invoking(() => builder.Property(a => a.StringValue).HasColumnName("String")) - .Should().Throw() + .Should() + .Throw() .WithMessage("The configuration of DbConnectionPlus is frozen and can no longer be modified."); } @@ -32,10 +35,11 @@ public void Property_InvalidExpression_ShouldThrow() var builder = new EntityTypeBuilder(); Invoking(() => builder.Property(a => a.Id.ToString())) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The expression 'a => a.Id.ToString()' is not a valid property access expression. The expression " + - "should represent a simple property access: 'a => a.MyProperty'.*" + "The expression 'a => a.Id.ToString()' is not a valid property access expression. The expression " + + "should represent a simple property access: 'a => a.MyProperty'.*" ); } @@ -46,11 +50,9 @@ public void Property_ShouldGetPropertyBuilder() var propertyBuilder = builder.Property(a => a.Id); - propertyBuilder - .Should().NotBeNull(); + propertyBuilder.Should().NotBeNull(); - builder.Property(a => a.Id) - .Should().BeSameAs(propertyBuilder); + builder.Property(a => a.Id).Should().BeSameAs(propertyBuilder); } [Fact] @@ -64,20 +66,15 @@ public void PropertyBuilders_ShouldGetBuildersOfConfiguredProperties() var propertyBuilders = ((IEntityTypeBuilder)builder).PropertyBuilders; - propertyBuilders - .Should().HaveCount(3); + propertyBuilders.Should().HaveCount(3); - propertyBuilders - .Should().ContainKeys("Id", "StringValue", "Int64Value"); + propertyBuilders.Should().ContainKeys("Id", "StringValue", "Int64Value"); - propertyBuilders["Id"] - .Should().BeSameAs(builder.Property(a => a.Id)); + propertyBuilders["Id"].Should().BeSameAs(builder.Property(a => a.Id)); - propertyBuilders["StringValue"] - .Should().BeSameAs(builder.Property(a => a.StringValue)); + propertyBuilders["StringValue"].Should().BeSameAs(builder.Property(a => a.StringValue)); - propertyBuilders["Int64Value"] - .Should().BeSameAs(builder.Property(a => a.Int64Value)); + propertyBuilders["Int64Value"].Should().BeSameAs(builder.Property(a => a.Int64Value)); } [Fact] @@ -85,9 +82,7 @@ public void ShouldGuardAgainstNullArguments() { var builder = new EntityTypeBuilder(); - ArgumentNullGuardVerifier.Verify(() => - builder.Property(a => a.Id) - ); + ArgumentNullGuardVerifier.Verify(() => builder.Property(a => a.Id)); } [Fact] @@ -95,8 +90,7 @@ public void TableName_NotConfigured_ShouldReturnNull() { var builder = new EntityTypeBuilder(); - ((IEntityTypeBuilder)builder).TableName - .Should().BeNull(); + ((IEntityTypeBuilder)builder).TableName.Should().BeNull(); } [Fact] @@ -106,8 +100,7 @@ public void ToTable_Configured_ShouldGetTableName() builder.ToTable("Entities"); - ((IEntityTypeBuilder)builder).TableName - .Should().Be("Entities"); + ((IEntityTypeBuilder)builder).TableName.Should().Be("Entities"); } [Fact] @@ -117,7 +110,6 @@ public void ToTable_ShouldSetTableName() builder.ToTable("Entities"); - ((IEntityTypeBuilder)builder).TableName - .Should().Be("Entities"); + ((IEntityTypeBuilder)builder).TableName.Should().Be("Entities"); } } diff --git a/tests/DbConnectionPlus.UnitTests/Converters/EnumConverterTests.cs b/tests/DbConnectionPlus.UnitTests/Converters/EnumConverterTests.cs index f64884d..e9e8171 100644 --- a/tests/DbConnectionPlus.UnitTests/Converters/EnumConverterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Converters/EnumConverterTests.cs @@ -7,27 +7,30 @@ public class EnumConverterTests : UnitTestsBase [Fact] public void ConvertValueToEnumMember_EmptyStringValue_ShouldThrow() => Invoking(() => EnumConverter.ConvertValueToEnumMember(string.Empty, typeof(TestEnum))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "Could not convert an empty string or a string that consists only of white-space characters to an " + - $"enum member of the type {typeof(TestEnum)}." + "Could not convert an empty string or a string that consists only of white-space characters to an " + + $"enum member of the type {typeof(TestEnum)}." ); [Fact] public void ConvertValueToEnumMember_NonEnumTargetType_ShouldThrow() { Invoking(() => EnumConverter.ConvertValueToEnumMember("ValueA", typeof(int))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the value 'ValueA' ({typeof(string)}) to an enum member of the type " + - $"{typeof(int)}, because the type {typeof(int)} is not an enum type.*" + $"Could not convert the value 'ValueA' ({typeof(string)}) to an enum member of the type " + + $"{typeof(int)}, because the type {typeof(int)} is not an enum type.*" ); Invoking(() => EnumConverter.ConvertValueToEnumMember("ValueA", typeof(int?))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the value 'ValueA' ({typeof(string)}) to an enum member of the type " + - $"{typeof(int?)}, because the type {typeof(int?)} is not an enum type.*" + $"Could not convert the value 'ValueA' ({typeof(string)}) to an enum member of the type " + + $"{typeof(int?)}, because the type {typeof(int?)} is not an enum type.*" ); } @@ -35,111 +38,112 @@ public void ConvertValueToEnumMember_NonEnumTargetType_ShouldThrow() public void ConvertValueToEnumMember_NonNullableTargetType_NullOrDBNullValue_ShouldThrow() { Invoking(() => EnumConverter.ConvertValueToEnumMember(DBNull.Value, typeof(TestEnum))) - .Should().Throw() - .WithMessage( - $"Could not convert {{null}} to an enum member of the type {typeof(TestEnum)}." - ); + .Should() + .Throw() + .WithMessage($"Could not convert {{null}} to an enum member of the type {typeof(TestEnum)}."); Invoking(() => EnumConverter.ConvertValueToEnumMember(null, typeof(TestEnum))) - .Should().Throw() - .WithMessage( - $"Could not convert {{null}} to an enum member of the type {typeof(TestEnum)}." - ); + .Should() + .Throw() + .WithMessage($"Could not convert {{null}} to an enum member of the type {typeof(TestEnum)}."); } [Fact] public void ConvertValueToEnumMember_NullableTargetType_NullOrDBNullValue_ShouldReturnNull() { - EnumConverter.ConvertValueToEnumMember(DBNull.Value, typeof(TestEnum?)) - .Should().BeNull(); + EnumConverter.ConvertValueToEnumMember(DBNull.Value, typeof(TestEnum?)).Should().BeNull(); - EnumConverter.ConvertValueToEnumMember(null, typeof(TestEnum?)) - .Should().BeNull(); + EnumConverter.ConvertValueToEnumMember(null, typeof(TestEnum?)).Should().BeNull(); } [Fact] public void ConvertValueToEnumMember_NumericValueNotMatchingAnyEnumMemberValue_ShouldThrow() => Invoking(() => EnumConverter.ConvertValueToEnumMember(999, typeof(TestEnum))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + - $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members." + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members." ); [Theory] [MemberData(nameof(GetConvertValueToEnumMemberTestData))] - public void - ConvertValueToEnumMember_ShouldConvertValueToEnumMember(object value, TestEnum expectedResult) + public void ConvertValueToEnumMember_ShouldConvertValueToEnumMember(object value, TestEnum expectedResult) { - EnumConverter.ConvertValueToEnumMember(value, typeof(TestEnum)) - .Should().Be(expectedResult); + EnumConverter.ConvertValueToEnumMember(value, typeof(TestEnum)).Should().Be(expectedResult); - EnumConverter.ConvertValueToEnumMember(value, typeof(TestEnum?)) - .Should().Be(expectedResult); + EnumConverter.ConvertValueToEnumMember(value, typeof(TestEnum?)).Should().Be(expectedResult); } [Fact] public void ConvertValueToEnumMember_StringValueNotMatchingAnyEnumMemberName_ShouldThrow() => Invoking(() => EnumConverter.ConvertValueToEnumMember("NonExistent", typeof(TestEnum))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + - "That string does not match any of the names of the enum's members." + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + + "That string does not match any of the names of the enum's members." ); [Fact] public void ConvertValueToEnumMember_ValueIsNeitherEnumValueNorStringNorNumeric_ShouldThrow() => Invoking(() => EnumConverter.ConvertValueToEnumMember(Guid.Empty, typeof(TestEnum))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the value '{Guid.Empty}' ({typeof(Guid)}) to an enum member of the type " + - $"{typeof(TestEnum)}. The value must either be an enum value of that type or a string or a numeric " + - "value." + $"Could not convert the value '{Guid.Empty}' ({typeof(Guid)}) to an enum member of the type " + + $"{typeof(TestEnum)}. The value must either be an enum value of that type or a string or a numeric " + + "value." ); [Fact] public void ConvertValueToEnumMember_ValueIsOfDifferentEnumType_ShouldThrow() => Invoking(() => EnumConverter.ConvertValueToEnumMember(ConsoleColor.Red, typeof(TestEnum))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the value 'Red' ({typeof(ConsoleColor)}) to an enum member of the type " + - $"{typeof(TestEnum)}. The value must either be an enum value of that type or a string or a numeric " + - "value." + $"Could not convert the value 'Red' ({typeof(ConsoleColor)}) to an enum member of the type " + + $"{typeof(TestEnum)}. The value must either be an enum value of that type or a string or a numeric " + + "value." ); [Fact] public void ConvertValueToEnumMember_WhitespaceStringValue_ShouldThrow() => Invoking(() => EnumConverter.ConvertValueToEnumMember(" ", typeof(TestEnum))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "Could not convert an empty string or a string that consists only of white-space characters to an " + - $"enum member of the type {typeof(TestEnum)}." + "Could not convert an empty string or a string that consists only of white-space characters to an " + + $"enum member of the type {typeof(TestEnum)}." ); [Fact] public void ConvertValueToEnumMemberOfT_EmptyStringValue_ShouldThrow() => Invoking(() => EnumConverter.ConvertValueToEnumMember(string.Empty)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "Could not convert an empty string or a string that consists only of white-space characters to an " + - $"enum member of the type {typeof(TestEnum)}." + "Could not convert an empty string or a string that consists only of white-space characters to an " + + $"enum member of the type {typeof(TestEnum)}." ); [Fact] public void ConvertValueToEnumMemberOfT_NonEnumTargetType_ShouldThrow() { Invoking(() => EnumConverter.ConvertValueToEnumMember("ValueA")) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the value 'ValueA' ({typeof(string)}) to an enum member of the type " + - $"{typeof(int)}, because the type {typeof(int)} is not an enum type.*" + $"Could not convert the value 'ValueA' ({typeof(string)}) to an enum member of the type " + + $"{typeof(int)}, because the type {typeof(int)} is not an enum type.*" ); Invoking(() => EnumConverter.ConvertValueToEnumMember("ValueA")) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the value 'ValueA' ({typeof(string)}) to an enum member of the type " + - $"{typeof(int?)}, because the type {typeof(int?)} is not an enum type.*" + $"Could not convert the value 'ValueA' ({typeof(string)}) to an enum member of the type " + + $"{typeof(int?)}, because the type {typeof(int?)} is not an enum type.*" ); } @@ -147,143 +151,141 @@ public void ConvertValueToEnumMemberOfT_NonEnumTargetType_ShouldThrow() public void ConvertValueToEnumMemberOfT_NonNullableTargetType_NullOrDBNullValue_ShouldThrow() { Invoking(() => EnumConverter.ConvertValueToEnumMember(DBNull.Value)) - .Should().Throw() - .WithMessage( - $"Could not convert {{null}} to an enum member of the type {typeof(TestEnum)}." - ); + .Should() + .Throw() + .WithMessage($"Could not convert {{null}} to an enum member of the type {typeof(TestEnum)}."); Invoking(() => EnumConverter.ConvertValueToEnumMember(null)) - .Should().Throw() - .WithMessage( - $"Could not convert {{null}} to an enum member of the type {typeof(TestEnum)}." - ); + .Should() + .Throw() + .WithMessage($"Could not convert {{null}} to an enum member of the type {typeof(TestEnum)}."); } [Fact] public void ConvertValueToEnumMemberOfT_NullableTargetType_NullOrDBNullValue_ShouldReturnNull() { - EnumConverter.ConvertValueToEnumMember(DBNull.Value) - .Should().BeNull(); + EnumConverter.ConvertValueToEnumMember(DBNull.Value).Should().BeNull(); - EnumConverter.ConvertValueToEnumMember(null) - .Should().BeNull(); + EnumConverter.ConvertValueToEnumMember(null).Should().BeNull(); } [Fact] public void ConvertValueToEnumMemberOfT_NumericValueNotMatchingAnyEnumMemberValue_ShouldThrow() => Invoking(() => EnumConverter.ConvertValueToEnumMember(999)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + - $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members." + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members." ); [Theory] [MemberData(nameof(GetConvertValueToEnumMemberTestData))] - public void - ConvertValueToEnumMemberOfT_ShouldConvertValueToEnumMember(object value, TestEnum expectedResult) + public void ConvertValueToEnumMemberOfT_ShouldConvertValueToEnumMember(object value, TestEnum expectedResult) { - EnumConverter.ConvertValueToEnumMember(value) - .Should().Be(expectedResult); + EnumConverter.ConvertValueToEnumMember(value).Should().Be(expectedResult); - EnumConverter.ConvertValueToEnumMember(value) - .Should().Be(expectedResult); + EnumConverter.ConvertValueToEnumMember(value).Should().Be(expectedResult); } [Fact] public void ConvertValueToEnumMemberOfT_StringValueNotMatchingAnyEnumMemberName_ShouldThrow() => Invoking(() => EnumConverter.ConvertValueToEnumMember("NonExistent")) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + - "That string does not match any of the names of the enum's members." + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + + "That string does not match any of the names of the enum's members." ); [Fact] public void ConvertValueToEnumMemberOfT_ValueIsNeitherEnumValueNorStringNorNumeric_ShouldThrow() => Invoking(() => EnumConverter.ConvertValueToEnumMember(Guid.Empty)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the value '{Guid.Empty}' ({typeof(Guid)}) to an enum member of the type " + - $"{typeof(TestEnum)}. The value must either be an enum value of that type or a string or a numeric " + - "value." + $"Could not convert the value '{Guid.Empty}' ({typeof(Guid)}) to an enum member of the type " + + $"{typeof(TestEnum)}. The value must either be an enum value of that type or a string or a numeric " + + "value." ); [Fact] public void ConvertValueToEnumMemberOfT_ValueIsOfDifferentEnumType_ShouldThrow() => Invoking(() => EnumConverter.ConvertValueToEnumMember(ConsoleColor.Red)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the value 'Red' ({typeof(ConsoleColor)}) to an enum member of the type " + - $"{typeof(TestEnum)}. The value must either be an enum value of that type or a string or a numeric " + - "value." + $"Could not convert the value 'Red' ({typeof(ConsoleColor)}) to an enum member of the type " + + $"{typeof(TestEnum)}. The value must either be an enum value of that type or a string or a numeric " + + "value." ); [Fact] public void ConvertValueToEnumMemberOfT_WhitespaceStringValue_ShouldThrow() => Invoking(() => EnumConverter.ConvertValueToEnumMember(" ")) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "Could not convert an empty string or a string that consists only of white-space characters to an " + - $"enum member of the type {typeof(TestEnum)}." + "Could not convert an empty string or a string that consists only of white-space characters to an " + + $"enum member of the type {typeof(TestEnum)}." ); public static IEnumerable<(object value, TestEnum expectedResult)> GetConvertValueToEnumMemberTestData() => - [ - ((short)1, TestEnum.Value1), - ((short)2, TestEnum.Value2), - ((short)3, TestEnum.Value3), - ((short)4, TestEnum.Value4), - ((short)5, TestEnum.Value5), - (1, TestEnum.Value1), - (2, TestEnum.Value2), - (3, TestEnum.Value3), - (4, TestEnum.Value4), - (5, TestEnum.Value5), - (1L, TestEnum.Value1), - (2L, TestEnum.Value2), - (3L, TestEnum.Value3), - (4L, TestEnum.Value4), - (5L, TestEnum.Value5), - ((byte)1, TestEnum.Value1), - ((byte)2, TestEnum.Value2), - ((byte)3, TestEnum.Value3), - ((byte)4, TestEnum.Value4), - ((byte)5, TestEnum.Value5), - ((float)1.0, TestEnum.Value1), - ((float)2.0, TestEnum.Value2), - ((float)3.0, TestEnum.Value3), - ((float)4.0, TestEnum.Value4), - ((float)5.0, TestEnum.Value5), - (1.0, TestEnum.Value1), - (2.0, TestEnum.Value2), - (3.0, TestEnum.Value3), - (4.0, TestEnum.Value4), - (5.0, TestEnum.Value5), - ((decimal)1.0, TestEnum.Value1), - ((decimal)2.0, TestEnum.Value2), - ((decimal)3.0, TestEnum.Value3), - ((decimal)4.0, TestEnum.Value4), - ((decimal)5.0, TestEnum.Value5), - ("Value1", TestEnum.Value1), - ("Value2", TestEnum.Value2), - ("Value3", TestEnum.Value3), - ("Value4", TestEnum.Value4), - ("Value5", TestEnum.Value5), - ("VALUE1", TestEnum.Value1), - ("VALUE2", TestEnum.Value2), - ("VALUE3", TestEnum.Value3), - ("VALUE4", TestEnum.Value4), - ("VALUE5", TestEnum.Value5), - ("1", TestEnum.Value1), - ("2", TestEnum.Value2), - ("3", TestEnum.Value3), - ("4", TestEnum.Value4), - ("5", TestEnum.Value5), - (TestEnum.Value1, TestEnum.Value1), - (TestEnum.Value2, TestEnum.Value2), - (TestEnum.Value3, TestEnum.Value3), - (TestEnum.Value4, TestEnum.Value4), - (TestEnum.Value5, TestEnum.Value5) - ]; + [ + ((short)1, TestEnum.Value1), + ((short)2, TestEnum.Value2), + ((short)3, TestEnum.Value3), + ((short)4, TestEnum.Value4), + ((short)5, TestEnum.Value5), + (1, TestEnum.Value1), + (2, TestEnum.Value2), + (3, TestEnum.Value3), + (4, TestEnum.Value4), + (5, TestEnum.Value5), + (1L, TestEnum.Value1), + (2L, TestEnum.Value2), + (3L, TestEnum.Value3), + (4L, TestEnum.Value4), + (5L, TestEnum.Value5), + ((byte)1, TestEnum.Value1), + ((byte)2, TestEnum.Value2), + ((byte)3, TestEnum.Value3), + ((byte)4, TestEnum.Value4), + ((byte)5, TestEnum.Value5), + ((float)1.0, TestEnum.Value1), + ((float)2.0, TestEnum.Value2), + ((float)3.0, TestEnum.Value3), + ((float)4.0, TestEnum.Value4), + ((float)5.0, TestEnum.Value5), + (1.0, TestEnum.Value1), + (2.0, TestEnum.Value2), + (3.0, TestEnum.Value3), + (4.0, TestEnum.Value4), + (5.0, TestEnum.Value5), + ((decimal)1.0, TestEnum.Value1), + ((decimal)2.0, TestEnum.Value2), + ((decimal)3.0, TestEnum.Value3), + ((decimal)4.0, TestEnum.Value4), + ((decimal)5.0, TestEnum.Value5), + ("Value1", TestEnum.Value1), + ("Value2", TestEnum.Value2), + ("Value3", TestEnum.Value3), + ("Value4", TestEnum.Value4), + ("Value5", TestEnum.Value5), + ("VALUE1", TestEnum.Value1), + ("VALUE2", TestEnum.Value2), + ("VALUE3", TestEnum.Value3), + ("VALUE4", TestEnum.Value4), + ("VALUE5", TestEnum.Value5), + ("1", TestEnum.Value1), + ("2", TestEnum.Value2), + ("3", TestEnum.Value3), + ("4", TestEnum.Value4), + ("5", TestEnum.Value5), + (TestEnum.Value1, TestEnum.Value1), + (TestEnum.Value2, TestEnum.Value2), + (TestEnum.Value3, TestEnum.Value3), + (TestEnum.Value4, TestEnum.Value4), + (TestEnum.Value5, TestEnum.Value5), + ]; } diff --git a/tests/DbConnectionPlus.UnitTests/Converters/EnumSerializerTests.cs b/tests/DbConnectionPlus.UnitTests/Converters/EnumSerializerTests.cs index 7faf6db..d813393 100644 --- a/tests/DbConnectionPlus.UnitTests/Converters/EnumSerializerTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Converters/EnumSerializerTests.cs @@ -7,7 +7,8 @@ public class EnumSerializerTests : UnitTestsBase [Fact] public void SerializeEnum_InvalidEnumSerializationMode_ShouldThrow() => Invoking(() => EnumSerializer.SerializeEnum(TestEnum.Value3, (EnumSerializationMode)999)) - .Should().Throw() + .Should() + .Throw() .WithMessage( $"The {nameof(EnumSerializationMode)} '999' ({typeof(EnumSerializationMode)}) is not supported.*" ); @@ -27,9 +28,7 @@ public void SerializeEnum_ShouldSerializeEnumValueAccordingToSerializationMode( TestEnum enumValue, EnumSerializationMode enumSerializationMode, object expectedResult - ) => - EnumSerializer.SerializeEnum(enumValue, enumSerializationMode) - .Should().Be(expectedResult); + ) => EnumSerializer.SerializeEnum(enumValue, enumSerializationMode).Should().Be(expectedResult); [Fact] public void ShouldGuardAgainstNullArguments() => diff --git a/tests/DbConnectionPlus.UnitTests/Converters/ValueConverterTests.cs b/tests/DbConnectionPlus.UnitTests/Converters/ValueConverterTests.cs index 8a43d95..eb4e2c7 100644 --- a/tests/DbConnectionPlus.UnitTests/Converters/ValueConverterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Converters/ValueConverterTests.cs @@ -75,8 +75,10 @@ public void CanConvert_ShouldDetermineIfConversionIsPossible( #pragma warning restore RCS1163 // Unused parameter #pragma warning restore xUnit1026 // Theory methods should use all of their parameters ) => - ValueConverter.CanConvert(sourceType, targetType) - .Should().Be( + ValueConverter + .CanConvert(sourceType, targetType) + .Should() + .Be( expectedCanConvert, $"{sourceType} should {(expectedCanConvert ? "" : "not ")}be convertible to {targetType}" ); @@ -86,42 +88,44 @@ public void ConvertValueToType_CharTargetType_StringWithLengthOneValue_ShouldGet { var character = Generate.Single(); - ValueConverter.ConvertValueToType(character.ToString(), typeof(char)) - .Should().Be(character); + ValueConverter.ConvertValueToType(character.ToString(), typeof(char)).Should().Be(character); - ValueConverter.ConvertValueToType(character.ToString(), typeof(char?)) - .Should().Be(character); + ValueConverter.ConvertValueToType(character.ToString(), typeof(char?)).Should().Be(character); } [Fact] public void ConvertValueToType_CharTargetType_ValueIsStringWithLengthNotOne_ShouldThrow() { Invoking(() => ValueConverter.ConvertValueToType(string.Empty, typeof(char))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly one " + - "character long." + $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly one " + + "character long." ); Invoking(() => ValueConverter.ConvertValueToType(string.Empty, typeof(char?))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the string '' to the type {typeof(char?)}. The string must be exactly one " + - "character long." + $"Could not convert the string '' to the type {typeof(char?)}. The string must be exactly one " + + "character long." ); Invoking(() => ValueConverter.ConvertValueToType("ab", typeof(char))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly one " + - "character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly one " + + "character long." ); Invoking(() => ValueConverter.ConvertValueToType("ab", typeof(char?))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char?)}. The string must be exactly one " + - "character long." + $"Could not convert the string 'ab' to the type {typeof(char?)}. The string must be exactly one " + + "character long." ); } @@ -138,14 +142,15 @@ string cultureName // into two different dates depending on the locale of the machine that runs the code. var expectedDate = new DateOnly(2026, 3, 4); - RunUnderCulture(cultureName, () => - { - ValueConverter.ConvertValueToType("03/04/2026") - .Should().Be(expectedDate); + RunUnderCulture( + cultureName, + () => + { + ValueConverter.ConvertValueToType("03/04/2026").Should().Be(expectedDate); - ValueConverter.ConvertValueToType("03/04/2026", typeof(DateOnly)) - .Should().Be(expectedDate); - }); + ValueConverter.ConvertValueToType("03/04/2026", typeof(DateOnly)).Should().Be(expectedDate); + } + ); } [Theory] @@ -162,13 +167,16 @@ public void ConvertValueToType_DateAndTimeStringValue_ShouldRoundTripUnderAnyCul var dateOnly = new DateOnly(2026, 3, 4); var timeOnly = new TimeOnly(14, 30, 0); - RunUnderCulture(cultureName, () => - { - AssertRoundTrips(timeSpan); - AssertRoundTrips(dateTimeOffset); - AssertRoundTrips(dateOnly); - AssertRoundTrips(timeOnly); - }); + RunUnderCulture( + cultureName, + () => + { + AssertRoundTrips(timeSpan); + AssertRoundTrips(dateTimeOffset); + AssertRoundTrips(dateOnly); + AssertRoundTrips(timeOnly); + } + ); // Converts the value to its String representation and back, both through the converter itself, so the // assertion is that the writing half and the reading half agree - not that either matches a literal. @@ -176,30 +184,35 @@ static void AssertRoundTrips(TValue value) { var text = ValueConverter.ConvertValueToType(value); - ValueConverter.ConvertValueToType(text) - .Should().Be(value, $"{typeof(TValue)} written as '{text}' should read back unchanged"); + ValueConverter + .ConvertValueToType(text) + .Should() + .Be(value, $"{typeof(TValue)} written as '{text}' should read back unchanged"); - ValueConverter.ConvertValueToType(text, typeof(TValue)) - .Should().Be(value, $"{typeof(TValue)} written as '{text}' should read back unchanged"); + ValueConverter + .ConvertValueToType(text, typeof(TValue)) + .Should() + .Be(value, $"{typeof(TValue)} written as '{text}' should read back unchanged"); } } [Fact] - public void - ConvertValueToType_EnumTargetType_IntegerValueNotMatchingAnyEnumMemberValue_ShouldThrow() + public void ConvertValueToType_EnumTargetType_IntegerValueNotMatchingAnyEnumMemberValue_ShouldThrow() { Invoking(() => ValueConverter.ConvertValueToType(999, typeof(TestEnum))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + - $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); Invoking(() => ValueConverter.ConvertValueToType(999, typeof(TestEnum?))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + - $"{typeof(TestEnum?)}. That value does not match any of the values of the enum's members.*" + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + + $"{typeof(TestEnum?)}. That value does not match any of the values of the enum's members.*" ); } @@ -208,29 +221,28 @@ public void ConvertValueToType_EnumTargetType_ShouldConvertToEnumMember() { var enumValue = Generate.Single(); - ValueConverter.ConvertValueToType((int)enumValue, typeof(TestEnum)) - .Should().Be(enumValue); + ValueConverter.ConvertValueToType((int)enumValue, typeof(TestEnum)).Should().Be(enumValue); - ValueConverter.ConvertValueToType((int)enumValue, typeof(TestEnum?)) - .Should().Be(enumValue); + ValueConverter.ConvertValueToType((int)enumValue, typeof(TestEnum?)).Should().Be(enumValue); } [Fact] - public void - ConvertValueToType_EnumTargetType_StringValueNotMatchingAnyEnumMemberName_ShouldThrow() + public void ConvertValueToType_EnumTargetType_StringValueNotMatchingAnyEnumMemberName_ShouldThrow() { Invoking(() => ValueConverter.ConvertValueToType("NonExistent", typeof(TestEnum))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + - "That string does not match any of the names of the enum's members.*" + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + + "That string does not match any of the names of the enum's members.*" ); Invoking(() => ValueConverter.ConvertValueToType("NonExistent", typeof(TestEnum?))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum?)}. " + - "That string does not match any of the names of the enum's members.*" + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum?)}. " + + "That string does not match any of the names of the enum's members.*" ); } @@ -238,17 +250,19 @@ public void public void ConvertValueToType_NonNullableTargetType_NullOrDBNullValue_ShouldThrow() { Invoking(() => ValueConverter.ConvertValueToType(DBNull.Value, typeof(DateTime))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the value {{DBNull}} to the type {typeof(DateTime)}, because the " + - "type is non-nullable.*" + $"Could not convert the value {{DBNull}} to the type {typeof(DateTime)}, because the " + + "type is non-nullable.*" ); Invoking(() => ValueConverter.ConvertValueToType(null, typeof(DateTime))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the value {{null}} to the type {typeof(DateTime)}, because the type is " + - "non-nullable.*" + $"Could not convert the value {{null}} to the type {typeof(DateTime)}, because the type is " + + "non-nullable.*" ); } @@ -279,17 +293,13 @@ public void ConvertValueToType_NullableSourceType_ShouldConvertValueToTargetType [Fact] public void ConvertValueToType_NullableTargetType_NullOrDBNullValue_ShouldReturnNull() { - ValueConverter.ConvertValueToType(DBNull.Value, typeof(object)) - .Should().BeNull(); + ValueConverter.ConvertValueToType(DBNull.Value, typeof(object)).Should().BeNull(); - ValueConverter.ConvertValueToType(DBNull.Value, typeof(int?)) - .Should().BeNull(); + ValueConverter.ConvertValueToType(DBNull.Value, typeof(int?)).Should().BeNull(); - ValueConverter.ConvertValueToType(null, typeof(object)) - .Should().BeNull(); + ValueConverter.ConvertValueToType(null, typeof(object)).Should().BeNull(); - ValueConverter.ConvertValueToType(null, typeof(int?)) - .Should().BeNull(); + ValueConverter.ConvertValueToType(null, typeof(int?)).Should().BeNull(); } [Theory] @@ -333,39 +343,41 @@ public void ConvertValueToType_ShouldConvertValueToType( if (result is byte[] resultBytes && expectedTargetValue is byte[] expectedTargetValueBytes) { resultBytes - .Should().BeEquivalentTo( + .Should() + .BeEquivalentTo( expectedTargetValueBytes, - $"{sourceValue.ToDebugString()} converted to {targetType} should be " + - $"{expectedTargetValue.ToDebugString()}" + $"{sourceValue.ToDebugString()} converted to {targetType} should be " + + $"{expectedTargetValue.ToDebugString()}" ); } else { result - .Should().Be( + .Should() + .Be( expectedTargetValue, - $"{sourceValue.ToDebugString()} converted to {targetType} should be " + - $"{expectedTargetValue.ToDebugString()}" + $"{sourceValue.ToDebugString()} converted to {targetType} should be " + + $"{expectedTargetValue.ToDebugString()}" ); } } else { Invoking(() => ValueConverter.ConvertValueToType(sourceValue, targetType)) - .Should().Throw() - .WithMessage( - $"Could not convert the value {sourceValue.ToDebugString()} to the type {targetType}.*" - ); + .Should() + .Throw() + .WithMessage($"Could not convert the value {sourceValue.ToDebugString()} to the type {targetType}.*"); } } [Fact] public void ConvertValueToType_ValueCannotBeConvertedToTargetType_ShouldThrow() => Invoking(() => ValueConverter.ConvertValueToType("NotADate", typeof(DateTime))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the value 'NotADate' ({typeof(string)}) to the type {typeof(DateTime)}. See " + - "inner exception for details.*" + $"Could not convert the value 'NotADate' ({typeof(string)}) to the type {typeof(DateTime)}. See " + + "inner exception for details.*" ) .WithInnerException() .WithMessage("The string 'NotADate' was not recognized as a valid DateTime.*"); @@ -375,61 +387,64 @@ public void ConvertValueToTypeOfT_CharTargetType_StringWithLengthOneValue_Should { var character = Generate.Single(); - ValueConverter.ConvertValueToType(character.ToString()) - .Should().Be(character); + ValueConverter.ConvertValueToType(character.ToString()).Should().Be(character); - ValueConverter.ConvertValueToType(character.ToString()) - .Should().Be(character); + ValueConverter.ConvertValueToType(character.ToString()).Should().Be(character); } [Fact] public void ConvertValueToTypeOfT_CharTargetType_ValueIsStringWithLengthNotOne_ShouldThrow() { Invoking(() => ValueConverter.ConvertValueToType(string.Empty)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly one " + - "character long." + $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly one " + + "character long." ); Invoking(() => ValueConverter.ConvertValueToType(string.Empty)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the string '' to the type {typeof(char?)}. The string must be exactly one " + - "character long." + $"Could not convert the string '' to the type {typeof(char?)}. The string must be exactly one " + + "character long." ); Invoking(() => ValueConverter.ConvertValueToType("ab")) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly one " + - "character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly one " + + "character long." ); Invoking(() => ValueConverter.ConvertValueToType("ab")) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char?)}. The string must be exactly one " + - "character long." + $"Could not convert the string 'ab' to the type {typeof(char?)}. The string must be exactly one " + + "character long." ); } [Fact] - public void - ConvertValueToTypeOfT_EnumTargetType_IntegerValueNotMatchingAnyEnumMemberValue_ShouldThrow() + public void ConvertValueToTypeOfT_EnumTargetType_IntegerValueNotMatchingAnyEnumMemberValue_ShouldThrow() { Invoking(() => ValueConverter.ConvertValueToType(999)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + - $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); Invoking(() => ValueConverter.ConvertValueToType(999)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + - $"{typeof(TestEnum?)}. That value does not match any of the values of the enum's members.*" + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + + $"{typeof(TestEnum?)}. That value does not match any of the values of the enum's members.*" ); } @@ -438,29 +453,28 @@ public void ConvertValueToTypeOfT_EnumTargetType_ShouldConvertToEnumMember() { var enumValue = Generate.Single(); - ValueConverter.ConvertValueToType((int)enumValue) - .Should().Be(enumValue); + ValueConverter.ConvertValueToType((int)enumValue).Should().Be(enumValue); - ValueConverter.ConvertValueToType((int)enumValue) - .Should().Be(enumValue); + ValueConverter.ConvertValueToType((int)enumValue).Should().Be(enumValue); } [Fact] - public void - ConvertValueToTypeOfT_EnumTargetType_StringValueNotMatchingAnyEnumMemberName_ShouldThrow() + public void ConvertValueToTypeOfT_EnumTargetType_StringValueNotMatchingAnyEnumMemberName_ShouldThrow() { Invoking(() => ValueConverter.ConvertValueToType("NonExistent")) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + - "That string does not match any of the names of the enum's members.*" + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + + "That string does not match any of the names of the enum's members.*" ); Invoking(() => ValueConverter.ConvertValueToType("NonExistent")) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum?)}. " + - "That string does not match any of the names of the enum's members.*" + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum?)}. " + + "That string does not match any of the names of the enum's members.*" ); } @@ -468,17 +482,19 @@ public void public void ConvertValueToTypeOfT_NonNullableTargetType_NullOrDBNullValue_ShouldThrow() { Invoking(() => ValueConverter.ConvertValueToType(DBNull.Value)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the value {{DBNull}} to the type {typeof(DateTime)}, because the " + - "type is non-nullable.*" + $"Could not convert the value {{DBNull}} to the type {typeof(DateTime)}, because the " + + "type is non-nullable.*" ); Invoking(() => ValueConverter.ConvertValueToType(null)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the value {{null}} to the type {typeof(DateTime)}, because the type is " + - "non-nullable.*" + $"Could not convert the value {{null}} to the type {typeof(DateTime)}, because the type is " + + "non-nullable.*" ); } @@ -509,17 +525,13 @@ public void ConvertValueToTypeOfT_NullableSourceType_ShouldConvertValueToTargetT [Fact] public void ConvertValueToTypeOfT_NullableTargetType_NullOrDBNullValue_ShouldReturnNull() { - ValueConverter.ConvertValueToType(DBNull.Value) - .Should().BeNull(); + ValueConverter.ConvertValueToType(DBNull.Value).Should().BeNull(); - ValueConverter.ConvertValueToType(DBNull.Value) - .Should().BeNull(); + ValueConverter.ConvertValueToType(DBNull.Value).Should().BeNull(); - ValueConverter.ConvertValueToType(null) - .Should().BeNull(); + ValueConverter.ConvertValueToType(null).Should().BeNull(); - ValueConverter.ConvertValueToType(null) - .Should().BeNull(); + ValueConverter.ConvertValueToType(null).Should().BeNull(); } [Theory] @@ -558,49 +570,53 @@ public void ConvertValueToTypeOfT_ShouldConvertValueToType( { if (expectedCanConvert) { - var result = MaterializerFactoryHelper.MakeValueConverterConvertValueToTypeMethod(targetType) + var result = MaterializerFactoryHelper + .MakeValueConverterConvertValueToTypeMethod(targetType) .Invoke(null, [sourceValue]); if (result is byte[] resultBytes && expectedTargetValue is byte[] expectedTargetValueBytes) { resultBytes - .Should().BeEquivalentTo( + .Should() + .BeEquivalentTo( expectedTargetValueBytes, - $"{sourceValue.ToDebugString()} converted to {targetType} should be " + - $"{expectedTargetValue.ToDebugString()}" + $"{sourceValue.ToDebugString()} converted to {targetType} should be " + + $"{expectedTargetValue.ToDebugString()}" ); } else { result - .Should().Be( + .Should() + .Be( expectedTargetValue, - $"{sourceValue.ToDebugString()} converted to {targetType} should be " + - $"{expectedTargetValue.ToDebugString()}" + $"{sourceValue.ToDebugString()} converted to {targetType} should be " + + $"{expectedTargetValue.ToDebugString()}" ); } } else { Invoking(() => - MaterializerFactoryHelper.MakeValueConverterConvertValueToTypeMethod(targetType) + MaterializerFactoryHelper + .MakeValueConverterConvertValueToTypeMethod(targetType) .Invoke(null, [sourceValue]) ) - .Should().Throw() + .Should() + .Throw() .WithInnerException() - .WithMessage( - $"Could not convert the value {sourceValue.ToDebugString()} to the type {targetType}.*" - ); + .WithMessage($"Could not convert the value {sourceValue.ToDebugString()} to the type {targetType}.*"); } } [Fact] public void ConvertValueToTypeOfT_ValueCannotBeConvertedToTargetType_ShouldThrow() => Invoking(() => ValueConverter.ConvertValueToType("NotADate")) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not convert the value 'NotADate' ({typeof(string)}) to the type {typeof(DateTime)}. See " + - "inner exception for details.*" + $"Could not convert the value 'NotADate' ({typeof(string)}) to the type {typeof(DateTime)}. See " + + "inner exception for details.*" ) .WithInnerException() .WithMessage("The string 'NotADate' was not recognized as a valid DateTime.*"); @@ -631,9 +647,9 @@ private static void RunUnderCulture(string cultureName, Action assertions) // Without ICU, every culture collapses into the invariant one and the test would pass while proving // nothing. de-DE and fr-FR both separate decimals with a comma; the invariant culture uses a dot. Assert.SkipWhen( - cultureName != "en-US" && - culture.NumberFormat.NumberDecimalSeparator == - CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator, + cultureName != "en-US" + && culture.NumberFormat.NumberDecimalSeparator + == CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator, $"Globalization is in invariant mode, so '{cultureName}' is not a real culture here." ); @@ -652,13 +668,12 @@ private static void RunUnderCulture(string cultureName, Action assertions) } public static IEnumerable<( - Type SourceType, - Type TargetType, - bool ExpectedCanConvert, - object SourceValue, - object ExpectedTargetValue - )> - GetConvertTestData() + Type SourceType, + Type TargetType, + bool ExpectedCanConvert, + object SourceValue, + object ExpectedTargetValue + )> GetConvertTestData() { var faker = new Faker(); @@ -735,52 +750,190 @@ object ExpectedTargetValue (typeof(char), typeof(ulong), true, charValue, (ulong)charValue), (typeof(DateOnly), typeof(DateOnly), true, dateOnlyValue, dateOnlyValue), (typeof(DateOnly), typeof(object), true, dateOnlyValue, dateOnlyValue), - (typeof(DateOnly), typeof(string), true, dateOnlyValue, dateOnlyValue.ToString("O", CultureInfo.InvariantCulture)), + ( + typeof(DateOnly), + typeof(string), + true, + dateOnlyValue, + dateOnlyValue.ToString("O", CultureInfo.InvariantCulture) + ), (typeof(DateTime), typeof(DateOnly), true, dateOnlyValue.ToDateTime(TimeOnly.MinValue), dateOnlyValue), (typeof(DateTime), typeof(DateTime), true, dateTimeValue, dateTimeValue), (typeof(DateTime), typeof(object), true, dateTimeValue, dateTimeValue), - (typeof(DateTime), typeof(string), true, dateTimeValue, dateTimeValue.ToString("O", CultureInfo.InvariantCulture)), + ( + typeof(DateTime), + typeof(string), + true, + dateTimeValue, + dateTimeValue.ToString("O", CultureInfo.InvariantCulture) + ), (typeof(DateTimeOffset), typeof(DateTimeOffset), true, dateTimeOffsetValue, dateTimeOffsetValue), (typeof(DateTimeOffset), typeof(object), true, dateTimeOffsetValue, dateTimeOffsetValue), - (typeof(DateTimeOffset), typeof(string), true, dateTimeOffsetValue, dateTimeOffsetValue.ToString("O", CultureInfo.InvariantCulture)), + ( + typeof(DateTimeOffset), + typeof(string), + true, + dateTimeOffsetValue, + dateTimeOffsetValue.ToString("O", CultureInfo.InvariantCulture) + ), (typeof(decimal), typeof(bool), true, 1M, true), - (typeof(decimal), typeof(byte), true, decimalValue, Convert.ChangeType(decimalValue, typeof(byte), CultureInfo.InvariantCulture)), + ( + typeof(decimal), + typeof(byte), + true, + decimalValue, + Convert.ChangeType(decimalValue, typeof(byte), CultureInfo.InvariantCulture) + ), (typeof(decimal), typeof(decimal), true, decimalValue, decimalValue), - (typeof(decimal), typeof(double), true, decimalValue, Convert.ChangeType(decimalValue, typeof(double), CultureInfo.InvariantCulture)), - (typeof(decimal), typeof(short), true, decimalValue, Convert.ChangeType(decimalValue, typeof(short), CultureInfo.InvariantCulture)), - (typeof(decimal), typeof(int), true, decimalValue, Convert.ChangeType(decimalValue, typeof(int), CultureInfo.InvariantCulture)), - (typeof(decimal), typeof(long), true, decimalValue, Convert.ChangeType(decimalValue, typeof(long), CultureInfo.InvariantCulture)), + ( + typeof(decimal), + typeof(double), + true, + decimalValue, + Convert.ChangeType(decimalValue, typeof(double), CultureInfo.InvariantCulture) + ), + ( + typeof(decimal), + typeof(short), + true, + decimalValue, + Convert.ChangeType(decimalValue, typeof(short), CultureInfo.InvariantCulture) + ), + ( + typeof(decimal), + typeof(int), + true, + decimalValue, + Convert.ChangeType(decimalValue, typeof(int), CultureInfo.InvariantCulture) + ), + ( + typeof(decimal), + typeof(long), + true, + decimalValue, + Convert.ChangeType(decimalValue, typeof(long), CultureInfo.InvariantCulture) + ), (typeof(decimal), typeof(object), true, decimalValue, decimalValue), - (typeof(decimal), typeof(sbyte), true, decimalValue, Convert.ChangeType(decimalValue, typeof(sbyte), CultureInfo.InvariantCulture)), - (typeof(decimal), typeof(float), true, decimalValue, Convert.ChangeType(decimalValue, typeof(float), CultureInfo.InvariantCulture)), + ( + typeof(decimal), + typeof(sbyte), + true, + decimalValue, + Convert.ChangeType(decimalValue, typeof(sbyte), CultureInfo.InvariantCulture) + ), + ( + typeof(decimal), + typeof(float), + true, + decimalValue, + Convert.ChangeType(decimalValue, typeof(float), CultureInfo.InvariantCulture) + ), (typeof(decimal), typeof(string), true, decimalValue, decimalValue.ToString(CultureInfo.InvariantCulture)), (typeof(decimal), typeof(TestEnum), true, (decimal)enumValue, enumValue), - (typeof(decimal), typeof(ushort), true, decimalValue, Convert.ChangeType(decimalValue, typeof(ushort), CultureInfo.InvariantCulture)), - (typeof(decimal), typeof(uint), true, decimalValue, Convert.ChangeType(decimalValue, typeof(uint), CultureInfo.InvariantCulture)), - (typeof(decimal), typeof(ulong), true, decimalValue, Convert.ChangeType(decimalValue, typeof(ulong), CultureInfo.InvariantCulture)), + ( + typeof(decimal), + typeof(ushort), + true, + decimalValue, + Convert.ChangeType(decimalValue, typeof(ushort), CultureInfo.InvariantCulture) + ), + ( + typeof(decimal), + typeof(uint), + true, + decimalValue, + Convert.ChangeType(decimalValue, typeof(uint), CultureInfo.InvariantCulture) + ), + ( + typeof(decimal), + typeof(ulong), + true, + decimalValue, + Convert.ChangeType(decimalValue, typeof(ulong), CultureInfo.InvariantCulture) + ), (typeof(double), typeof(bool), true, 1.0, true), - (typeof(double), typeof(byte), true, doubleValue, Convert.ChangeType(doubleValue, typeof(byte), CultureInfo.InvariantCulture)), - (typeof(double), typeof(decimal), true, doubleValue, Convert.ChangeType(doubleValue, typeof(decimal), CultureInfo.InvariantCulture)), + ( + typeof(double), + typeof(byte), + true, + doubleValue, + Convert.ChangeType(doubleValue, typeof(byte), CultureInfo.InvariantCulture) + ), + ( + typeof(double), + typeof(decimal), + true, + doubleValue, + Convert.ChangeType(doubleValue, typeof(decimal), CultureInfo.InvariantCulture) + ), (typeof(double), typeof(double), true, doubleValue, doubleValue), - (typeof(double), typeof(short), true, doubleValue, Convert.ChangeType(doubleValue, typeof(short), CultureInfo.InvariantCulture)), - (typeof(double), typeof(int), true, doubleValue, Convert.ChangeType(doubleValue, typeof(int), CultureInfo.InvariantCulture)), - (typeof(double), typeof(long), true, doubleValue, Convert.ChangeType(doubleValue, typeof(long), CultureInfo.InvariantCulture)), + ( + typeof(double), + typeof(short), + true, + doubleValue, + Convert.ChangeType(doubleValue, typeof(short), CultureInfo.InvariantCulture) + ), + ( + typeof(double), + typeof(int), + true, + doubleValue, + Convert.ChangeType(doubleValue, typeof(int), CultureInfo.InvariantCulture) + ), + ( + typeof(double), + typeof(long), + true, + doubleValue, + Convert.ChangeType(doubleValue, typeof(long), CultureInfo.InvariantCulture) + ), (typeof(double), typeof(object), true, doubleValue, doubleValue), - (typeof(double), typeof(sbyte), true, doubleValue, Convert.ChangeType(doubleValue, typeof(sbyte), CultureInfo.InvariantCulture)), - (typeof(double), typeof(float), true, doubleValue, Convert.ChangeType(doubleValue, typeof(float), CultureInfo.InvariantCulture)), + ( + typeof(double), + typeof(sbyte), + true, + doubleValue, + Convert.ChangeType(doubleValue, typeof(sbyte), CultureInfo.InvariantCulture) + ), + ( + typeof(double), + typeof(float), + true, + doubleValue, + Convert.ChangeType(doubleValue, typeof(float), CultureInfo.InvariantCulture) + ), (typeof(double), typeof(string), true, doubleValue, doubleValue.ToString(CultureInfo.InvariantCulture)), (typeof(double), typeof(TestEnum), true, (double)enumValue, enumValue), - (typeof(double), typeof(ushort), true, doubleValue, Convert.ChangeType(doubleValue, typeof(ushort), CultureInfo.InvariantCulture)), - (typeof(double), typeof(uint), true, doubleValue, Convert.ChangeType(doubleValue, typeof(uint), CultureInfo.InvariantCulture)), - (typeof(double), typeof(ulong), true, doubleValue, Convert.ChangeType(doubleValue, typeof(ulong), CultureInfo.InvariantCulture)), + ( + typeof(double), + typeof(ushort), + true, + doubleValue, + Convert.ChangeType(doubleValue, typeof(ushort), CultureInfo.InvariantCulture) + ), + ( + typeof(double), + typeof(uint), + true, + doubleValue, + Convert.ChangeType(doubleValue, typeof(uint), CultureInfo.InvariantCulture) + ), + ( + typeof(double), + typeof(ulong), + true, + doubleValue, + Convert.ChangeType(doubleValue, typeof(ulong), CultureInfo.InvariantCulture) + ), (typeof(Guid), typeof(byte[]), true, guidValue, guidValue.ToByteArray()), (typeof(Guid), typeof(Guid), true, guidValue, guidValue), (typeof(Guid), typeof(object), true, guidValue, guidValue), (typeof(Guid), typeof(string), true, guidValue, guidValue.ToString("D")), (typeof(short), typeof(bool), true, (short)1, true), - (typeof(short), typeof(byte), true, int16Value, (byte) int16Value), - (typeof(short), typeof(char), true, int16Value, (char) int16Value), - (typeof(short), typeof(decimal), true, int16Value, (decimal) int16Value), + (typeof(short), typeof(byte), true, int16Value, (byte)int16Value), + (typeof(short), typeof(char), true, int16Value, (char)int16Value), + (typeof(short), typeof(decimal), true, int16Value, (decimal)int16Value), (typeof(short), typeof(double), true, int16Value, (double)int16Value), (typeof(short), typeof(short), true, int16Value, int16Value), (typeof(short), typeof(int), true, int16Value, (int)int16Value), @@ -795,7 +948,7 @@ object ExpectedTargetValue (typeof(short), typeof(ulong), true, int16Value, (ulong)int16Value), (typeof(int), typeof(bool), true, 1, true), (typeof(int), typeof(byte), true, int32Value, (byte)int32Value), - (typeof(int), typeof(char), true, int32Value, (char) int32Value), + (typeof(int), typeof(char), true, int32Value, (char)int32Value), (typeof(int), typeof(decimal), true, int32Value, (decimal)int32Value), (typeof(int), typeof(double), true, int32Value, (double)int32Value), (typeof(int), typeof(short), true, int32Value, (short)int32Value), @@ -810,9 +963,9 @@ object ExpectedTargetValue (typeof(int), typeof(uint), true, int32Value, (uint)int32Value), (typeof(int), typeof(ulong), true, int32Value, (ulong)int32Value), (typeof(long), typeof(bool), true, (long)1, true), - (typeof(long), typeof(byte), true, int64Value, (byte) int64Value), - (typeof(long), typeof(char), true, int64Value, (char) int64Value), - (typeof(long), typeof(decimal), true, int64Value, (decimal) int64Value), + (typeof(long), typeof(byte), true, int64Value, (byte)int64Value), + (typeof(long), typeof(char), true, int64Value, (char)int64Value), + (typeof(long), typeof(decimal), true, int64Value, (decimal)int64Value), (typeof(long), typeof(double), true, int64Value, (double)int64Value), (typeof(long), typeof(short), true, int64Value, (short)int64Value), (typeof(long), typeof(int), true, int64Value, (int)int64Value), @@ -829,7 +982,7 @@ object ExpectedTargetValue (typeof(IntPtr), typeof(object), true, intPtrValue, intPtrValue), (typeof(sbyte), typeof(bool), true, (sbyte)1, true), (typeof(sbyte), typeof(byte), true, sbyteValue, (byte)sbyteValue), - (typeof(sbyte), typeof(char), true, sbyteValue, (char) sbyteValue), + (typeof(sbyte), typeof(char), true, sbyteValue, (char)sbyteValue), (typeof(sbyte), typeof(decimal), true, sbyteValue, (decimal)sbyteValue), (typeof(sbyte), typeof(double), true, sbyteValue, (double)sbyteValue), (typeof(sbyte), typeof(short), true, sbyteValue, (short)sbyteValue), @@ -844,26 +997,110 @@ object ExpectedTargetValue (typeof(sbyte), typeof(uint), true, sbyteValue, (uint)sbyteValue), (typeof(sbyte), typeof(ulong), true, sbyteValue, (ulong)sbyteValue), (typeof(float), typeof(bool), true, (float)1, true), - (typeof(float), typeof(byte), true, singleValue, Convert.ChangeType(singleValue, typeof(byte), CultureInfo.InvariantCulture)), - (typeof(float), typeof(decimal), true, singleValue, Convert.ChangeType(singleValue, typeof(decimal), CultureInfo.InvariantCulture)), - (typeof(float), typeof(double), true, singleValue, Convert.ChangeType(singleValue, typeof(double), CultureInfo.InvariantCulture)), - (typeof(float), typeof(short), true, singleValue, Convert.ChangeType(singleValue, typeof(short), CultureInfo.InvariantCulture)), - (typeof(float), typeof(int), true, singleValue, Convert.ChangeType(singleValue, typeof(int), CultureInfo.InvariantCulture)), - (typeof(float), typeof(long), true, singleValue, Convert.ChangeType(singleValue, typeof(long), CultureInfo.InvariantCulture)), + ( + typeof(float), + typeof(byte), + true, + singleValue, + Convert.ChangeType(singleValue, typeof(byte), CultureInfo.InvariantCulture) + ), + ( + typeof(float), + typeof(decimal), + true, + singleValue, + Convert.ChangeType(singleValue, typeof(decimal), CultureInfo.InvariantCulture) + ), + ( + typeof(float), + typeof(double), + true, + singleValue, + Convert.ChangeType(singleValue, typeof(double), CultureInfo.InvariantCulture) + ), + ( + typeof(float), + typeof(short), + true, + singleValue, + Convert.ChangeType(singleValue, typeof(short), CultureInfo.InvariantCulture) + ), + ( + typeof(float), + typeof(int), + true, + singleValue, + Convert.ChangeType(singleValue, typeof(int), CultureInfo.InvariantCulture) + ), + ( + typeof(float), + typeof(long), + true, + singleValue, + Convert.ChangeType(singleValue, typeof(long), CultureInfo.InvariantCulture) + ), (typeof(float), typeof(object), true, singleValue, singleValue), - (typeof(float), typeof(sbyte), true, singleValue, Convert.ChangeType(singleValue, typeof(sbyte), CultureInfo.InvariantCulture)), - (typeof(float), typeof(float), true, singleValue, Convert.ChangeType(singleValue, typeof(float), CultureInfo.InvariantCulture)), + ( + typeof(float), + typeof(sbyte), + true, + singleValue, + Convert.ChangeType(singleValue, typeof(sbyte), CultureInfo.InvariantCulture) + ), + ( + typeof(float), + typeof(float), + true, + singleValue, + Convert.ChangeType(singleValue, typeof(float), CultureInfo.InvariantCulture) + ), (typeof(float), typeof(string), true, singleValue, singleValue.ToString(CultureInfo.InvariantCulture)), (typeof(float), typeof(TestEnum), true, (float)enumValue, enumValue), - (typeof(float), typeof(ushort), true, singleValue, Convert.ChangeType(singleValue, typeof(ushort), CultureInfo.InvariantCulture)), - (typeof(float), typeof(uint), true, singleValue, Convert.ChangeType(singleValue, typeof(uint), CultureInfo.InvariantCulture)), - (typeof(float), typeof(ulong), true, singleValue, Convert.ChangeType(singleValue, typeof(ulong), CultureInfo.InvariantCulture)), + ( + typeof(float), + typeof(ushort), + true, + singleValue, + Convert.ChangeType(singleValue, typeof(ushort), CultureInfo.InvariantCulture) + ), + ( + typeof(float), + typeof(uint), + true, + singleValue, + Convert.ChangeType(singleValue, typeof(uint), CultureInfo.InvariantCulture) + ), + ( + typeof(float), + typeof(ulong), + true, + singleValue, + Convert.ChangeType(singleValue, typeof(ulong), CultureInfo.InvariantCulture) + ), (typeof(string), typeof(bool), true, "True", true), (typeof(string), typeof(byte), true, byteValue.ToString(CultureInfo.InvariantCulture), byteValue), (typeof(string), typeof(char), true, charValue.ToString(CultureInfo.InvariantCulture), charValue), - (typeof(string), typeof(DateOnly), true, dateOnlyValue.ToString("O", CultureInfo.InvariantCulture), dateOnlyValue), - (typeof(string), typeof(DateTime), true, dateTimeValue.ToString("O", CultureInfo.InvariantCulture), dateTimeValue), - (typeof(string), typeof(DateTimeOffset), true, dateTimeOffsetValue.ToString("O", CultureInfo.InvariantCulture), dateTimeOffsetValue), + ( + typeof(string), + typeof(DateOnly), + true, + dateOnlyValue.ToString("O", CultureInfo.InvariantCulture), + dateOnlyValue + ), + ( + typeof(string), + typeof(DateTime), + true, + dateTimeValue.ToString("O", CultureInfo.InvariantCulture), + dateTimeValue + ), + ( + typeof(string), + typeof(DateTimeOffset), + true, + dateTimeOffsetValue.ToString("O", CultureInfo.InvariantCulture), + dateTimeOffsetValue + ), (typeof(string), typeof(decimal), true, decimalValue.ToString(CultureInfo.InvariantCulture), decimalValue), (typeof(string), typeof(double), true, doubleValue.ToString(CultureInfo.InvariantCulture), doubleValue), (typeof(string), typeof(Guid), true, guidValue.ToString("D"), guidValue), @@ -875,7 +1112,13 @@ object ExpectedTargetValue (typeof(string), typeof(float), true, singleValue.ToString(CultureInfo.InvariantCulture), singleValue), (typeof(string), typeof(string), true, stringValue, stringValue), (typeof(string), typeof(TestEnum), true, enumValue.ToString(), enumValue), - (typeof(string), typeof(TimeSpan), true, timeSpanValue.ToString("g", CultureInfo.InvariantCulture), timeSpanValue), + ( + typeof(string), + typeof(TimeSpan), + true, + timeSpanValue.ToString("g", CultureInfo.InvariantCulture), + timeSpanValue + ), (typeof(string), typeof(ushort), true, uint16Value.ToString(CultureInfo.InvariantCulture), uint16Value), (typeof(string), typeof(uint), true, uint32Value.ToString(CultureInfo.InvariantCulture), uint32Value), (typeof(string), typeof(ulong), true, uint64Value.ToString(CultureInfo.InvariantCulture), uint64Value), @@ -894,16 +1137,28 @@ object ExpectedTargetValue (typeof(TestEnum), typeof(uint), true, enumValue, (uint)enumValue), (typeof(TestEnum), typeof(ulong), true, enumValue, (ulong)enumValue), (typeof(TimeOnly), typeof(object), true, timeOnlyValue, timeOnlyValue), - (typeof(TimeOnly), typeof(string), true, timeOnlyValue, timeOnlyValue.ToString("O", CultureInfo.InvariantCulture)), + ( + typeof(TimeOnly), + typeof(string), + true, + timeOnlyValue, + timeOnlyValue.ToString("O", CultureInfo.InvariantCulture) + ), (typeof(TimeOnly), typeof(TimeOnly), true, timeOnlyValue, timeOnlyValue), (typeof(TimeSpan), typeof(object), true, timeSpanValue, timeSpanValue), - (typeof(TimeSpan), typeof(string), true, timeSpanValue, timeSpanValue.ToString("g", CultureInfo.InvariantCulture)), + ( + typeof(TimeSpan), + typeof(string), + true, + timeSpanValue, + timeSpanValue.ToString("g", CultureInfo.InvariantCulture) + ), (typeof(TimeSpan), typeof(TimeOnly), true, timeSpanValue, TimeOnly.FromTimeSpan(timeSpanValue)), (typeof(TimeSpan), typeof(TimeSpan), true, timeSpanValue, timeSpanValue), (typeof(ushort), typeof(bool), true, (ushort)1, true), - (typeof(ushort), typeof(byte), true, uint16Value, (byte) uint16Value), - (typeof(ushort), typeof(char), true, uint16Value, (char) uint16Value), - (typeof(ushort), typeof(decimal), true, uint16Value, (decimal) uint16Value), + (typeof(ushort), typeof(byte), true, uint16Value, (byte)uint16Value), + (typeof(ushort), typeof(char), true, uint16Value, (char)uint16Value), + (typeof(ushort), typeof(decimal), true, uint16Value, (decimal)uint16Value), (typeof(ushort), typeof(double), true, uint16Value, (double)uint16Value), (typeof(ushort), typeof(short), true, uint16Value, (short)uint16Value), (typeof(ushort), typeof(int), true, uint16Value, (int)uint16Value), @@ -917,9 +1172,9 @@ object ExpectedTargetValue (typeof(ushort), typeof(uint), true, uint16Value, (uint)uint16Value), (typeof(ushort), typeof(ulong), true, uint16Value, (ulong)uint16Value), (typeof(uint), typeof(bool), true, (uint)1, true), - (typeof(uint), typeof(byte), true, uint32Value, (byte) uint32Value), - (typeof(uint), typeof(char), true, uint32Value, (char) uint32Value), - (typeof(uint), typeof(decimal), true, uint32Value, (decimal) uint32Value), + (typeof(uint), typeof(byte), true, uint32Value, (byte)uint32Value), + (typeof(uint), typeof(char), true, uint32Value, (char)uint32Value), + (typeof(uint), typeof(decimal), true, uint32Value, (decimal)uint32Value), (typeof(uint), typeof(double), true, uint32Value, (double)uint32Value), (typeof(uint), typeof(int), true, uint32Value, (int)uint32Value), (typeof(uint), typeof(int), true, uint32Value, (int)uint32Value), @@ -933,9 +1188,9 @@ object ExpectedTargetValue (typeof(uint), typeof(uint), true, uint32Value, uint32Value), (typeof(uint), typeof(ulong), true, uint32Value, (ulong)uint32Value), (typeof(ulong), typeof(bool), true, (ulong)1, true), - (typeof(ulong), typeof(byte), true, uint64Value, (byte) uint64Value), - (typeof(ulong), typeof(char), true, uint64Value, (char) uint64Value), - (typeof(ulong), typeof(decimal), true, uint64Value, (decimal) uint64Value), + (typeof(ulong), typeof(byte), true, uint64Value, (byte)uint64Value), + (typeof(ulong), typeof(char), true, uint64Value, (char)uint64Value), + (typeof(ulong), typeof(decimal), true, uint64Value, (decimal)uint64Value), (typeof(ulong), typeof(double), true, uint64Value, (double)uint64Value), (typeof(ulong), typeof(short), true, uint64Value, (short)uint64Value), (typeof(ulong), typeof(int), true, uint64Value, (int)uint64Value), diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlConfigurationExtensionsTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlConfigurationExtensionsTests.cs index 0f56ab9..128d024 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlConfigurationExtensionsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlConfigurationExtensionsTests.cs @@ -1,7 +1,6 @@ using MySqlConnector; using RentADeveloper.DbConnectionPlus.DatabaseAdapters.MySql; - namespace RentADeveloper.DbConnectionPlus.UnitTests.DatabaseAdapters.MySql; public class MySqlConfigurationExtensionsTests : UnitTestsBase @@ -23,4 +22,4 @@ public void UseMySql_ShouldRegisterMySqlAdapter() adapter.Should().NotBeNull(); adapter.Should().BeOfType(); } -} \ No newline at end of file +} diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlDatabaseAdapterTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlDatabaseAdapterTests.cs index 0bb8156..2291edd 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlDatabaseAdapterTests.cs @@ -13,11 +13,9 @@ public void BindParameterValue_BytesValue_ShouldSetDbTypeAndValue() this.adapter.BindParameterValue(parameter, value); - parameter.DbType - .Should().Be(DbType.Binary); + parameter.DbType.Should().Be(DbType.Binary); - parameter.Value - .Should().Be(value); + parameter.Value.Should().Be(value); } [Fact] @@ -29,11 +27,9 @@ public void BindParameterValue_DateTimeValue_ShouldSetDbTypeAndValue() this.adapter.BindParameterValue(parameter, value); - parameter.DbType - .Should().Be(DbType.DateTime); + parameter.DbType.Should().Be(DbType.DateTime); - parameter.Value - .Should().Be(value); + parameter.Value.Should().Be(value); } [Fact] @@ -47,11 +43,9 @@ public void BindParameterValue_EnumValue_EnumSerializationModeIsIntegers_ShouldB this.adapter.BindParameterValue(parameter, enumValue); - parameter.DbType - .Should().Be(DbType.Int32); + parameter.DbType.Should().Be(DbType.Int32); - parameter.Value - .Should().Be((int)enumValue); + parameter.Value.Should().Be((int)enumValue); } [Fact] @@ -65,11 +59,9 @@ public void BindParameterValue_EnumValue_EnumSerializationModeIsStrings_ShouldBi this.adapter.BindParameterValue(parameter, enumValue); - parameter.DbType - .Should().Be(DbType.String); + parameter.DbType.Should().Be(DbType.String); - parameter.Value - .Should().Be(enumValue.ToString()); + parameter.Value.Should().Be(enumValue.ToString()); } [Fact] @@ -81,34 +73,30 @@ public void BindParameterValue_ShouldSetValue() this.adapter.BindParameterValue(parameter, value); - parameter.Value - .Should().Be(value); + parameter.Value.Should().Be(value); } [Fact] public void EntityManipulator_ShouldReturnManipulator() => - this.adapter.EntityManipulator - .Should().BeOfType(); + this.adapter.EntityManipulator.Should().BeOfType(); [Fact] public void FormatParameterName_ShouldFormatParameterName() => - this.adapter.FormatParameterName("Param1") - .Should().Be("@Param1"); + this.adapter.FormatParameterName("Param1").Should().Be("@Param1"); [Fact] public void GetDataType_EnumType_EnumSerializationModeIsInteger_ShouldReturnInt() { - this.adapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Integers) - .Should().Be("INT"); + this.adapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Integers).Should().Be("INT"); - this.adapter.GetDataType(typeof(TestEnum?), EnumSerializationMode.Integers) - .Should().Be("INT"); + this.adapter.GetDataType(typeof(TestEnum?), EnumSerializationMode.Integers).Should().Be("INT"); } [Fact] public void GetDataType_EnumType_EnumSerializationModeIsNotSupported_ShouldThrow() => Invoking(() => this.adapter.GetDataType(typeof(TestEnum), (EnumSerializationMode)999)) - .Should().Throw() + .Should() + .Throw() .WithMessage( $"The {nameof(EnumSerializationMode)} '999' ({typeof(EnumSerializationMode)}) is not supported.*" ); @@ -116,11 +104,9 @@ public void GetDataType_EnumType_EnumSerializationModeIsNotSupported_ShouldThrow [Fact] public void GetDataType_EnumType_EnumSerializationModeIsString_ShouldReturnVarchar() { - this.adapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Strings) - .Should().Be("VARCHAR(200)"); + this.adapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Strings).Should().Be("VARCHAR(200)"); - this.adapter.GetDataType(typeof(TestEnum?), EnumSerializationMode.Strings) - .Should().Be("VARCHAR(200)"); + this.adapter.GetDataType(typeof(TestEnum?), EnumSerializationMode.Strings).Should().Be("VARCHAR(200)"); } [Theory] @@ -155,50 +141,42 @@ public void GetDataType_EnumType_EnumSerializationModeIsString_ShouldReturnVarch [InlineData(typeof(TimeSpan?), "TIME")] [InlineData(typeof(TimeSpan), "TIME")] public void GetDataType_SupportedTypeType_ShouldReturnMySqlDataType(Type type, string expectedResult) => - this.adapter.GetDataType(type, EnumSerializationMode.Strings) - .Should().Be(expectedResult); + this.adapter.GetDataType(type, EnumSerializationMode.Strings).Should().Be(expectedResult); [Fact] public void GetDataType_UnsupportedType_ShouldThrow() => Invoking(() => this.adapter.GetDataType(typeof(Entity), EnumSerializationMode.Strings)) - .Should().Throw() + .Should() + .Throw() .WithMessage($"Could not map the type {typeof(Entity)} to a MySQL data type.*"); [Fact] public void QuoteIdentifier_ShouldQuoteIdentifier() => - this.adapter.QuoteIdentifier("MyTable") - .Should().Be("`MyTable`"); + this.adapter.QuoteIdentifier("MyTable").Should().Be("`MyTable`"); [Fact] public void QuoteTemporaryTableName_ShouldQuoteTableName() => - this.adapter.QuoteTemporaryTableName("TempTable", this.MockDbConnection) - .Should().Be("`TempTable`"); + this.adapter.QuoteTemporaryTableName("TempTable", this.MockDbConnection).Should().Be("`TempTable`"); [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - this.adapter.BindParameterValue(Substitute.For(), null) - ); + ArgumentNullGuardVerifier.Verify(() => this.adapter.BindParameterValue(Substitute.For(), null)); ArgumentNullGuardVerifier.Verify(() => this.adapter.WasSqlStatementCancelledByCancellationToken(new(), CancellationToken.None) ); - ArgumentNullGuardVerifier.Verify(() => - this.adapter.GetDataType(typeof(int), EnumSerializationMode.Integers) - ); + ArgumentNullGuardVerifier.Verify(() => this.adapter.GetDataType(typeof(int), EnumSerializationMode.Integers)); } [Fact] public void TemporaryTableBuilder_ShouldReturnBuilder() => - this.adapter.TemporaryTableBuilder - .Should().BeOfType(); + this.adapter.TemporaryTableBuilder.Should().BeOfType(); [Fact] public void WasSqlStatementCancelledByCancellationToken_ShouldAlwaysReturnFalse() => - this.adapter.WasSqlStatementCancelledByCancellationToken(new(), CancellationToken.None) - .Should().BeFalse(); + this.adapter.WasSqlStatementCancelledByCancellationToken(new(), CancellationToken.None).Should().BeFalse(); private readonly MySqlDatabaseAdapter adapter = new(); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlTemporaryTableBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlTemporaryTableBuilderTests.cs index 1e1c562..04a8d68 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlTemporaryTableBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlTemporaryTableBuilderTests.cs @@ -7,15 +7,13 @@ public class MySqlTemporaryTableBuilderTests : UnitTestsBase [Fact] public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() { - Invoking(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) - ) - .Should().Throw(); + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int))) + .Should() + .Throw(); - Invoking(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) - ) - .Should().Throw(); + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int))) + .Should() + .Throw(); } [Fact] @@ -24,20 +22,20 @@ public async Task BuildTemporaryTableAsync_NameIsNullOrEmptyOrWhitespace_ShouldT await Invoking(() => this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) ) - .Should().ThrowAsync(); + .Should() + .ThrowAsync(); await Invoking(() => this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) ) - .Should().ThrowAsync(); + .Should() + .ThrowAsync(); } [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - new MySqlTemporaryTableBuilder(new()) - ); + ArgumentNullGuardVerifier.Verify(() => new MySqlTemporaryTableBuilder(new())); ArgumentNullGuardVerifier.Verify(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleConfigurationExtensionsTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleConfigurationExtensionsTests.cs index bf3714f..b153733 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleConfigurationExtensionsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleConfigurationExtensionsTests.cs @@ -22,4 +22,4 @@ public void UseOracle_ShouldRegisterOracleAdapter() adapter.Should().NotBeNull(); adapter.Should().BeOfType(); } -} \ No newline at end of file +} diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs index 230ea95..7108ecf 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs @@ -7,8 +7,7 @@ public class OracleDatabaseAdapterTests : UnitTestsBase { [Fact] public void AllowTemporaryTables_ShouldReturnFalsePerDefault() => - OracleDatabaseAdapter.AllowTemporaryTables - .Should().BeFalse(); + OracleDatabaseAdapter.AllowTemporaryTables.Should().BeFalse(); [Fact] public void BindParameterValue_BytesValue_ShouldSetDbTypeAndValue() @@ -19,11 +18,9 @@ public void BindParameterValue_BytesValue_ShouldSetDbTypeAndValue() this.adapter.BindParameterValue(parameter, value); - parameter.DbType - .Should().Be(DbType.Binary); + parameter.DbType.Should().Be(DbType.Binary); - parameter.Value - .Should().Be(value); + parameter.Value.Should().Be(value); } [Fact] @@ -35,11 +32,9 @@ public void BindParameterValue_DateOnlyValue_ShouldSetDbTypeAndValue() this.adapter.BindParameterValue(parameter, value); - parameter.DbType - .Should().Be(DbType.Date); + parameter.DbType.Should().Be(DbType.Date); - parameter.Value - .Should().Be(value.ToDateTime(TimeOnly.MinValue)); + parameter.Value.Should().Be(value.ToDateTime(TimeOnly.MinValue)); } [Fact] @@ -51,11 +46,9 @@ public void BindParameterValue_DateTimeValue_ShouldSetDbTypeAndValue() this.adapter.BindParameterValue(parameter, value); - parameter.DbType - .Should().Be(DbType.DateTime); + parameter.DbType.Should().Be(DbType.DateTime); - parameter.Value - .Should().Be(value); + parameter.Value.Should().Be(value); } [Fact] @@ -69,11 +62,9 @@ public void BindParameterValue_EnumValue_EnumSerializationModeIsIntegers_ShouldB this.adapter.BindParameterValue(parameter, enumValue); - parameter.DbType - .Should().Be(DbType.Int32); + parameter.DbType.Should().Be(DbType.Int32); - parameter.Value - .Should().Be((int)enumValue); + parameter.Value.Should().Be((int)enumValue); } [Fact] @@ -87,11 +78,9 @@ public void BindParameterValue_EnumValue_EnumSerializationModeIsStrings_ShouldBi this.adapter.BindParameterValue(parameter, enumValue); - parameter.DbType - .Should().Be(DbType.String); + parameter.DbType.Should().Be(DbType.String); - parameter.Value - .Should().Be(enumValue.ToString()); + parameter.Value.Should().Be(enumValue.ToString()); } [Fact] @@ -103,11 +92,9 @@ public void BindParameterValue_GuidValue_ShouldSetDbTypeAndValue() this.adapter.BindParameterValue(parameter, value); - parameter.DbType - .Should().Be(DbType.Binary); + parameter.DbType.Should().Be(DbType.Binary); - parameter.Value - .Should().Be(value); + parameter.Value.Should().Be(value); } [Fact] @@ -119,8 +106,7 @@ public void BindParameterValue_ShouldSetValue() this.adapter.BindParameterValue(parameter, value); - parameter.Value - .Should().Be(value); + parameter.Value.Should().Be(value); } [Fact] @@ -132,40 +118,34 @@ public void BindParameterValue_TimeOnlyValue_ShouldSetDbTypeAndValue() this.adapter.BindParameterValue(parameter, value); - parameter.DbType - .Should().Be(DbType.Time); + parameter.DbType.Should().Be(DbType.Time); - (parameter as OracleParameter)?.OracleDbType - .Should().Be(OracleDbType.IntervalDS); + (parameter as OracleParameter)?.OracleDbType.Should().Be(OracleDbType.IntervalDS); - parameter.Value - .Should().Be(value.ToTimeSpan()); + parameter.Value.Should().Be(value.ToTimeSpan()); } [Fact] public void EntityManipulator_ShouldReturnManipulator() => - this.adapter.EntityManipulator - .Should().BeOfType(); + this.adapter.EntityManipulator.Should().BeOfType(); [Fact] public void FormatParameterName_ShouldFormatParameterName() => - this.adapter.FormatParameterName("Param1") - .Should().Be(":\"Param1\""); + this.adapter.FormatParameterName("Param1").Should().Be(":\"Param1\""); [Fact] public void GetDataType_EnumType_EnumSerializationModeIsInteger_ShouldReturnNumber() { - this.adapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Integers) - .Should().Be("NUMBER(10)"); + this.adapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Integers).Should().Be("NUMBER(10)"); - this.adapter.GetDataType(typeof(TestEnum?), EnumSerializationMode.Integers) - .Should().Be("NUMBER(10)"); + this.adapter.GetDataType(typeof(TestEnum?), EnumSerializationMode.Integers).Should().Be("NUMBER(10)"); } [Fact] public void GetDataType_EnumType_EnumSerializationModeIsNotSupported_ShouldThrow() => Invoking(() => this.adapter.GetDataType(typeof(TestEnum), (EnumSerializationMode)999)) - .Should().Throw() + .Should() + .Throw() .WithMessage( $"The {nameof(EnumSerializationMode)} '999' ({typeof(EnumSerializationMode)}) is not supported.*" ); @@ -173,11 +153,9 @@ public void GetDataType_EnumType_EnumSerializationModeIsNotSupported_ShouldThrow [Fact] public void GetDataType_EnumType_EnumSerializationModeIsString_ShouldReturnNVarchar2() { - this.adapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Strings) - .Should().Be("NVARCHAR2(200)"); + this.adapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Strings).Should().Be("NVARCHAR2(200)"); - this.adapter.GetDataType(typeof(TestEnum?), EnumSerializationMode.Strings) - .Should().Be("NVARCHAR2(200)"); + this.adapter.GetDataType(typeof(TestEnum?), EnumSerializationMode.Strings).Should().Be("NVARCHAR2(200)"); } [Theory] @@ -214,29 +192,28 @@ public void GetDataType_EnumType_EnumSerializationModeIsString_ShouldReturnNVarc [InlineData(typeof(TimeSpan?), "INTERVAL DAY TO SECOND")] [InlineData(typeof(TimeSpan), "INTERVAL DAY TO SECOND")] public void GetDataType_SupportedTypeType_ShouldReturnSqlServerDataType(Type type, string expectedResult) => - this.adapter.GetDataType(type, EnumSerializationMode.Strings) - .Should().Be(expectedResult); + this.adapter.GetDataType(type, EnumSerializationMode.Strings).Should().Be(expectedResult); [Fact] public void GetDataType_UnsupportedType_ShouldThrow() => Invoking(() => this.adapter.GetDataType(typeof(Entity), EnumSerializationMode.Strings)) - .Should().Throw() + .Should() + .Throw() .WithMessage($"Could not map the type {typeof(Entity)} to an Oracle data type.*"); [Fact] public void GetDbType_EnumType_EnumSerializationModeIsInteger_ShouldReturnInt32() { - this.adapter.GetDbType(typeof(TestEnum), EnumSerializationMode.Integers) - .Should().Be(DbType.Int32); + this.adapter.GetDbType(typeof(TestEnum), EnumSerializationMode.Integers).Should().Be(DbType.Int32); - this.adapter.GetDbType(typeof(TestEnum?), EnumSerializationMode.Integers) - .Should().Be(DbType.Int32); + this.adapter.GetDbType(typeof(TestEnum?), EnumSerializationMode.Integers).Should().Be(DbType.Int32); } [Fact] public void GetDbType_EnumType_EnumSerializationModeIsNotSupported_ShouldThrow() => Invoking(() => this.adapter.GetDbType(typeof(TestEnum), (EnumSerializationMode)999)) - .Should().Throw() + .Should() + .Throw() .WithMessage( $"The {nameof(EnumSerializationMode)} '999' ({typeof(EnumSerializationMode)}) is not supported.*" ); @@ -244,11 +221,9 @@ public void GetDbType_EnumType_EnumSerializationModeIsNotSupported_ShouldThrow() [Fact] public void GetDbType_EnumType_EnumSerializationModeIsString_ShouldReturnString() { - this.adapter.GetDbType(typeof(TestEnum), EnumSerializationMode.Strings) - .Should().Be(DbType.String); + this.adapter.GetDbType(typeof(TestEnum), EnumSerializationMode.Strings).Should().Be(DbType.String); - this.adapter.GetDbType(typeof(TestEnum?), EnumSerializationMode.Strings) - .Should().Be(DbType.String); + this.adapter.GetDbType(typeof(TestEnum?), EnumSerializationMode.Strings).Should().Be(DbType.String); } [Theory] @@ -285,39 +260,33 @@ public void GetDbType_EnumType_EnumSerializationModeIsString_ShouldReturnString( [InlineData(typeof(TimeSpan?), DbType.Time)] [InlineData(typeof(TimeSpan), DbType.Time)] public void GetDbType_SupportedTypeType_ShouldReturnSqlServerDataType(Type type, DbType expectedResult) => - this.adapter.GetDbType(type, EnumSerializationMode.Strings) - .Should().Be(expectedResult); + this.adapter.GetDbType(type, EnumSerializationMode.Strings).Should().Be(expectedResult); [Fact] public void GetDbType_UnsupportedType_ShouldThrow() => Invoking(() => this.adapter.GetDbType(typeof(Entity), EnumSerializationMode.Strings)) - .Should().Throw() + .Should() + .Throw() .WithMessage($"Could not map the type {typeof(Entity)} to a {typeof(DbType)} value.*"); [Fact] public void QuoteIdentifier_ShouldQuoteIdentifier() => - this.adapter.QuoteIdentifier("MyTable") - .Should().Be("\"MyTable\""); + this.adapter.QuoteIdentifier("MyTable").Should().Be("\"MyTable\""); [Fact] public void QuoteTemporaryTableName_ShouldQuoteTableName() { this.MockDbCommand.ExecuteScalar().Returns("MockPrefix"); - this.adapter.QuoteTemporaryTableName("TempTable", this.MockDbConnection) - .Should().Be("\"MockPrefixTempTable\""); + this.adapter.QuoteTemporaryTableName("TempTable", this.MockDbConnection).Should().Be("\"MockPrefixTempTable\""); } [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - this.adapter.BindParameterValue(Substitute.For(), null) - ); + ArgumentNullGuardVerifier.Verify(() => this.adapter.BindParameterValue(Substitute.For(), null)); - ArgumentNullGuardVerifier.Verify(() => - this.adapter.SupportsTemporaryTables(this.MockDbConnection) - ); + ArgumentNullGuardVerifier.Verify(() => this.adapter.SupportsTemporaryTables(this.MockDbConnection)); ArgumentNullGuardVerifier.Verify(() => this.adapter.WasSqlStatementCancelledByCancellationToken(new(), CancellationToken.None) @@ -331,8 +300,7 @@ public void SupportsTemporaryTables_OracleVersionEqualToOrGreaterThan18_ShouldRe // Oracle version is 18 or higher. this.MockDbDataReader.Read().Returns(true); - this.adapter.SupportsTemporaryTables(this.MockDbConnection) - .Should().BeTrue(); + this.adapter.SupportsTemporaryTables(this.MockDbConnection).Should().BeTrue(); } [Fact] @@ -342,8 +310,7 @@ public void SupportsTemporaryTables_OracleVersionLessThan18_ShouldReturnFalse() // the Oracle version is lower than 18. this.MockDbDataReader.Read().Returns(false); - this.adapter.SupportsTemporaryTables(this.MockDbConnection) - .Should().BeFalse(); + this.adapter.SupportsTemporaryTables(this.MockDbConnection).Should().BeFalse(); } [Fact] @@ -352,12 +319,13 @@ public void TemporaryTableBuilder_AllowTemporaryTablesIsFalse_ShouldThrow() OracleDatabaseAdapter.AllowTemporaryTables = false; Invoking(() => this.adapter.TemporaryTableBuilder) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The temporary tables feature of DbConnectionPlus is currently disabled for Oracle databases. " + - $"To enable it set {typeof(OracleDatabaseAdapter)}.AllowTemporaryTables to true, but be sure to " + - "read the documentation first, because enabling this feature has implications for transaction " + - "management." + "The temporary tables feature of DbConnectionPlus is currently disabled for Oracle databases. " + + $"To enable it set {typeof(OracleDatabaseAdapter)}.AllowTemporaryTables to true, but be sure to " + + "read the documentation first, because enabling this feature has implications for transaction " + + "management." ); } @@ -366,8 +334,7 @@ public void TemporaryTableBuilder_AllowTemporaryTablesIsTrue_ShouldReturnBuilder { OracleDatabaseAdapter.AllowTemporaryTables = true; - this.adapter.TemporaryTableBuilder - .Should().BeOfType(); + this.adapter.TemporaryTableBuilder.Should().BeOfType(); } private readonly OracleDatabaseAdapter adapter = new(); diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleTemporaryTableBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleTemporaryTableBuilderTests.cs index 6f38992..8227b60 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleTemporaryTableBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleTemporaryTableBuilderTests.cs @@ -9,29 +9,27 @@ public void BuildTemporaryTable_AllowTemporaryTablesIsFalse_ShouldThrow() { OracleDatabaseAdapter.AllowTemporaryTables = false; - Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) - ) - .Should().Throw() + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int))) + .Should() + .Throw() .WithMessage( - "The temporary tables feature of DbConnectionPlus is currently disabled for Oracle databases. " + - $"To enable it set {typeof(OracleDatabaseAdapter)}.AllowTemporaryTables to true, but be sure to " + - "read the documentation first, because enabling this feature has implications for transaction " + - "management." + "The temporary tables feature of DbConnectionPlus is currently disabled for Oracle databases. " + + $"To enable it set {typeof(OracleDatabaseAdapter)}.AllowTemporaryTables to true, but be sure to " + + "read the documentation first, because enabling this feature has implications for transaction " + + "management." ); } [Fact] public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() { - Invoking(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) - ) - .Should().Throw(); + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int))) + .Should() + .Throw(); - Invoking(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) - ) - .Should().Throw(); + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int))) + .Should() + .Throw(); } [Fact] @@ -39,20 +37,16 @@ public Task BuildTemporaryTableAsync_AllowTemporaryTablesIsFalse_ShouldThrow() { OracleDatabaseAdapter.AllowTemporaryTables = false; - return Invoking(() => this.builder.BuildTemporaryTableAsync( - this.MockDbConnection, - null, - "Name", - new[] { 1 }, - typeof(int) - ) + return Invoking(() => + this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - "The temporary tables feature of DbConnectionPlus is currently disabled for Oracle databases. " + - $"To enable it set {typeof(OracleDatabaseAdapter)}.AllowTemporaryTables to true, but be sure to " + - "read the documentation first, because enabling this feature has implications for transaction " + - "management." + "The temporary tables feature of DbConnectionPlus is currently disabled for Oracle databases. " + + $"To enable it set {typeof(OracleDatabaseAdapter)}.AllowTemporaryTables to true, but be sure to " + + "read the documentation first, because enabling this feature has implications for transaction " + + "management." ); } @@ -62,20 +56,20 @@ public async Task BuildTemporaryTableAsync_NameIsNullOrEmptyOrWhitespace_ShouldT await Invoking(() => this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) ) - .Should().ThrowAsync(); + .Should() + .ThrowAsync(); await Invoking(() => this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) ) - .Should().ThrowAsync(); + .Should() + .ThrowAsync(); } [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - new OracleTemporaryTableBuilder(new()) - ); + ArgumentNullGuardVerifier.Verify(() => new OracleTemporaryTableBuilder(new())); ArgumentNullGuardVerifier.Verify(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlConfigurationExtensionsTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlConfigurationExtensionsTests.cs index b1245ab..b7ca612 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlConfigurationExtensionsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlConfigurationExtensionsTests.cs @@ -22,4 +22,4 @@ public void UsePostgreSql_ShouldRegisterPostgreSqlAdapter() adapter.Should().NotBeNull(); adapter.Should().BeOfType(); } -} \ No newline at end of file +} diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlDatabaseAdapterTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlDatabaseAdapterTests.cs index 4bcacc4..1da542a 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlDatabaseAdapterTests.cs @@ -14,11 +14,9 @@ public void BindParameterValue_BytesValue_ShouldSetDbTypeAndValue() this.adapter.BindParameterValue(parameter, value); - parameter.DbType - .Should().Be(DbType.Binary); + parameter.DbType.Should().Be(DbType.Binary); - parameter.Value - .Should().Be(value); + parameter.Value.Should().Be(value); } [Fact] @@ -30,11 +28,9 @@ public void BindParameterValue_DateTimeValue_ShouldSetDbTypeAndValue() this.adapter.BindParameterValue(parameter, value); - parameter.DbType - .Should().Be(DbType.DateTime2); + parameter.DbType.Should().Be(DbType.DateTime2); - parameter.Value - .Should().Be(value); + parameter.Value.Should().Be(value); } [Fact] @@ -48,11 +44,9 @@ public void BindParameterValue_EnumValue_EnumSerializationModeIsIntegers_ShouldB this.adapter.BindParameterValue(parameter, enumValue); - parameter.DbType - .Should().Be(DbType.Int32); + parameter.DbType.Should().Be(DbType.Int32); - parameter.Value - .Should().Be((int)enumValue); + parameter.Value.Should().Be((int)enumValue); } [Fact] @@ -66,11 +60,9 @@ public void BindParameterValue_EnumValue_EnumSerializationModeIsStrings_ShouldBi this.adapter.BindParameterValue(parameter, enumValue); - parameter.DbType - .Should().Be(DbType.String); + parameter.DbType.Should().Be(DbType.String); - parameter.Value - .Should().Be(enumValue.ToString()); + parameter.Value.Should().Be(enumValue.ToString()); } [Fact] @@ -82,34 +74,30 @@ public void BindParameterValue_ShouldSetValue() this.adapter.BindParameterValue(parameter, value); - parameter.Value - .Should().Be(value); + parameter.Value.Should().Be(value); } [Fact] public void EntityManipulator_ShouldReturnManipulator() => - this.adapter.EntityManipulator - .Should().BeOfType(); + this.adapter.EntityManipulator.Should().BeOfType(); [Fact] public void FormatParameterName_ShouldFormatParameterName() => - this.adapter.FormatParameterName("Param1") - .Should().Be("@Param1"); + this.adapter.FormatParameterName("Param1").Should().Be("@Param1"); [Fact] public void GetDataType_EnumType_EnumSerializationModeIsInteger_ShouldReturnInteger() { - this.adapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Integers) - .Should().Be("integer"); + this.adapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Integers).Should().Be("integer"); - this.adapter.GetDataType(typeof(TestEnum?), EnumSerializationMode.Integers) - .Should().Be("integer"); + this.adapter.GetDataType(typeof(TestEnum?), EnumSerializationMode.Integers).Should().Be("integer"); } [Fact] public void GetDataType_EnumType_EnumSerializationModeIsNotSupported_ShouldThrow() => Invoking(() => this.adapter.GetDataType(typeof(TestEnum), (EnumSerializationMode)999)) - .Should().Throw() + .Should() + .Throw() .WithMessage( $"The {nameof(EnumSerializationMode)} '999' ({typeof(EnumSerializationMode)}) is not supported.*" ); @@ -117,11 +105,11 @@ public void GetDataType_EnumType_EnumSerializationModeIsNotSupported_ShouldThrow [Fact] public void GetDataType_EnumType_EnumSerializationModeIsString_ShouldReturnCharacterVarying() { - this.adapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Strings) - .Should().Be("character varying(200)"); + this.adapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Strings).Should().Be("character varying(200)"); this.adapter.GetDataType(typeof(TestEnum?), EnumSerializationMode.Strings) - .Should().Be("character varying(200)"); + .Should() + .Be("character varying(200)"); } [Theory] @@ -156,13 +144,13 @@ public void GetDataType_EnumType_EnumSerializationModeIsString_ShouldReturnChara [InlineData(typeof(TimeSpan?), "interval")] [InlineData(typeof(TimeSpan), "interval")] public void GetDataType_SupportedTypeType_ShouldReturnPostgreSqlDataType(Type type, string expectedResult) => - this.adapter.GetDataType(type, EnumSerializationMode.Strings) - .Should().Be(expectedResult); + this.adapter.GetDataType(type, EnumSerializationMode.Strings).Should().Be(expectedResult); [Fact] public void GetDataType_UnsupportedType_ShouldThrow() => Invoking(() => this.adapter.GetDataType(typeof(Entity), EnumSerializationMode.Strings)) - .Should().Throw() + .Should() + .Throw() .WithMessage($"Could not map the type {typeof(Entity)} to a PostgreSQL data type.*"); [Theory] @@ -197,49 +185,40 @@ public void GetDataType_UnsupportedType_ShouldThrow() => [InlineData(typeof(TimeSpan?), NpgsqlDbType.Interval)] [InlineData(typeof(TimeSpan), NpgsqlDbType.Interval)] public void GetDbType_SupportedTypeType_ShouldReturnDbDataType(Type type, NpgsqlDbType expectedResult) => - this.adapter.GetDbType(type, EnumSerializationMode.Strings) - .Should().Be(expectedResult); + this.adapter.GetDbType(type, EnumSerializationMode.Strings).Should().Be(expectedResult); [Fact] public void GetDbType_UnsupportedType_ShouldThrow() => Invoking(() => this.adapter.GetDbType(typeof(Entity), EnumSerializationMode.Strings)) - .Should().Throw() + .Should() + .Throw() .WithMessage($"Could not map the type {typeof(Entity)} to a {typeof(NpgsqlDbType)} value.*"); [Fact] public void QuoteIdentifier_ShouldQuoteIdentifier() => - this.adapter.QuoteIdentifier("MyTable") - .Should().Be("\"MyTable\""); + this.adapter.QuoteIdentifier("MyTable").Should().Be("\"MyTable\""); [Fact] public void QuoteTemporaryTableName_ShouldQuoteTableName() => - this.adapter.QuoteTemporaryTableName("TempTable", this.MockDbConnection) - .Should().Be("\"TempTable\""); + this.adapter.QuoteTemporaryTableName("TempTable", this.MockDbConnection).Should().Be("\"TempTable\""); [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - this.adapter.BindParameterValue(Substitute.For(), null) - ); + ArgumentNullGuardVerifier.Verify(() => this.adapter.BindParameterValue(Substitute.For(), null)); ArgumentNullGuardVerifier.Verify(() => this.adapter.WasSqlStatementCancelledByCancellationToken(new(), CancellationToken.None) ); - ArgumentNullGuardVerifier.Verify(() => - this.adapter.GetDataType(typeof(int), EnumSerializationMode.Integers) - ); + ArgumentNullGuardVerifier.Verify(() => this.adapter.GetDataType(typeof(int), EnumSerializationMode.Integers)); - ArgumentNullGuardVerifier.Verify(() => - this.adapter.GetDbType(typeof(int), EnumSerializationMode.Integers) - ); + ArgumentNullGuardVerifier.Verify(() => this.adapter.GetDbType(typeof(int), EnumSerializationMode.Integers)); } [Fact] public void TemporaryTableBuilder_ShouldReturnBuilder() => - this.adapter.TemporaryTableBuilder - .Should().BeOfType(); + this.adapter.TemporaryTableBuilder.Should().BeOfType(); private readonly PostgreSqlDatabaseAdapter adapter = new(); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlTemporaryTableBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlTemporaryTableBuilderTests.cs index 3c0bc92..fd73617 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlTemporaryTableBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlTemporaryTableBuilderTests.cs @@ -7,15 +7,13 @@ public class PostgreSqlTemporaryTableBuilderTests : UnitTestsBase [Fact] public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() { - Invoking(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) - ) - .Should().Throw(); + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int))) + .Should() + .Throw(); - Invoking(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) - ) - .Should().Throw(); + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int))) + .Should() + .Throw(); } [Fact] @@ -24,20 +22,20 @@ public async Task BuildTemporaryTableAsync_NameIsNullOrEmptyOrWhitespace_ShouldT await Invoking(() => this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) ) - .Should().ThrowAsync(); + .Should() + .ThrowAsync(); await Invoking(() => this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) ) - .Should().ThrowAsync(); + .Should() + .ThrowAsync(); } [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - new PostgreSqlTemporaryTableBuilder(new()) - ); + ArgumentNullGuardVerifier.Verify(() => new PostgreSqlTemporaryTableBuilder(new())); ArgumentNullGuardVerifier.Verify(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerDatabaseAdapterTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerDatabaseAdapterTests.cs index 3ee9d1b..a449ae6 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerDatabaseAdapterTests.cs @@ -13,11 +13,9 @@ public void BindParameterValue_BytesValue_ShouldSetDbTypeAndValue() this.adapter.BindParameterValue(parameter, value); - parameter.DbType - .Should().Be(DbType.Binary); + parameter.DbType.Should().Be(DbType.Binary); - parameter.Value - .Should().Be(value); + parameter.Value.Should().Be(value); } [Fact] @@ -29,11 +27,9 @@ public void BindParameterValue_DateTimeValue_ShouldSetDbTypeAndValue() this.adapter.BindParameterValue(parameter, value); - parameter.DbType - .Should().Be(DbType.DateTime2); + parameter.DbType.Should().Be(DbType.DateTime2); - parameter.Value - .Should().Be(value); + parameter.Value.Should().Be(value); } [Fact] @@ -47,11 +43,9 @@ public void BindParameterValue_EnumValue_EnumSerializationModeIsIntegers_ShouldB this.adapter.BindParameterValue(parameter, enumValue); - parameter.DbType - .Should().Be(DbType.Int32); + parameter.DbType.Should().Be(DbType.Int32); - parameter.Value - .Should().Be((int)enumValue); + parameter.Value.Should().Be((int)enumValue); } [Fact] @@ -65,11 +59,9 @@ public void BindParameterValue_EnumValue_EnumSerializationModeIsStrings_ShouldBi this.adapter.BindParameterValue(parameter, enumValue); - parameter.DbType - .Should().Be(DbType.String); + parameter.DbType.Should().Be(DbType.String); - parameter.Value - .Should().Be(enumValue.ToString()); + parameter.Value.Should().Be(enumValue.ToString()); } [Fact] @@ -81,34 +73,30 @@ public void BindParameterValue_ShouldSetValue() this.adapter.BindParameterValue(parameter, value); - parameter.Value - .Should().Be(value); + parameter.Value.Should().Be(value); } [Fact] public void EntityManipulator_ShouldReturnManipulator() => - this.adapter.EntityManipulator - .Should().BeOfType(); + this.adapter.EntityManipulator.Should().BeOfType(); [Fact] public void FormatParameterName_ShouldFormatParameterName() => - this.adapter.FormatParameterName("Param1") - .Should().Be("@Param1"); + this.adapter.FormatParameterName("Param1").Should().Be("@Param1"); [Fact] public void GetDataType_EnumType_EnumSerializationModeIsInteger_ShouldReturnInt() { - this.adapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Integers) - .Should().Be("int"); + this.adapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Integers).Should().Be("int"); - this.adapter.GetDataType(typeof(TestEnum?), EnumSerializationMode.Integers) - .Should().Be("int"); + this.adapter.GetDataType(typeof(TestEnum?), EnumSerializationMode.Integers).Should().Be("int"); } [Fact] public void GetDataType_EnumType_EnumSerializationModeIsNotSupported_ShouldThrow() => Invoking(() => this.adapter.GetDataType(typeof(TestEnum), (EnumSerializationMode)999)) - .Should().Throw() + .Should() + .Throw() .WithMessage( $"The {nameof(EnumSerializationMode)} '999' ({typeof(EnumSerializationMode)}) is not supported.*" ); @@ -116,11 +104,9 @@ public void GetDataType_EnumType_EnumSerializationModeIsNotSupported_ShouldThrow [Fact] public void GetDataType_EnumType_EnumSerializationModeIsString_ShouldReturnNVarchar() { - this.adapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Strings) - .Should().Be("nvarchar(200)"); + this.adapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Strings).Should().Be("nvarchar(200)"); - this.adapter.GetDataType(typeof(TestEnum?), EnumSerializationMode.Strings) - .Should().Be("nvarchar(200)"); + this.adapter.GetDataType(typeof(TestEnum?), EnumSerializationMode.Strings).Should().Be("nvarchar(200)"); } [Theory] @@ -158,45 +144,38 @@ public void GetDataType_EnumType_EnumSerializationModeIsString_ShouldReturnNVarc [InlineData(typeof(TimeSpan?), "time")] [InlineData(typeof(TimeSpan), "time")] public void GetDataType_SupportedTypeType_ShouldReturnSqlServerDataType(Type type, string expectedResult) => - this.adapter.GetDataType(type, EnumSerializationMode.Strings) - .Should().Be(expectedResult); + this.adapter.GetDataType(type, EnumSerializationMode.Strings).Should().Be(expectedResult); [Fact] public void GetDataType_UnsupportedType_ShouldThrow() => Invoking(() => this.adapter.GetDataType(typeof(Entity), EnumSerializationMode.Strings)) - .Should().Throw() + .Should() + .Throw() .WithMessage($"Could not map the type {typeof(Entity)} to an SQL Server data type.*"); [Fact] public void QuoteIdentifier_ShouldQuoteIdentifier() => - this.adapter.QuoteIdentifier("MyTable") - .Should().Be("[MyTable]"); + this.adapter.QuoteIdentifier("MyTable").Should().Be("[MyTable]"); [Fact] public void QuoteTemporaryTableName_ShouldQuoteTableName() => - this.adapter.QuoteTemporaryTableName("TempTable", this.MockDbConnection) - .Should().Be("[#TempTable]"); + this.adapter.QuoteTemporaryTableName("TempTable", this.MockDbConnection).Should().Be("[#TempTable]"); [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - this.adapter.BindParameterValue(Substitute.For(), null) - ); + ArgumentNullGuardVerifier.Verify(() => this.adapter.BindParameterValue(Substitute.For(), null)); ArgumentNullGuardVerifier.Verify(() => this.adapter.WasSqlStatementCancelledByCancellationToken(new(), CancellationToken.None) ); - ArgumentNullGuardVerifier.Verify(() => - this.adapter.GetDataType(typeof(int), EnumSerializationMode.Integers) - ); + ArgumentNullGuardVerifier.Verify(() => this.adapter.GetDataType(typeof(int), EnumSerializationMode.Integers)); } [Fact] public void TemporaryTableBuilder_ShouldReturnBuilder() => - this.adapter.TemporaryTableBuilder - .Should().BeOfType(); + this.adapter.TemporaryTableBuilder.Should().BeOfType(); private readonly SqlServerDatabaseAdapter adapter = new(); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerTemporaryTableBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerTemporaryTableBuilderTests.cs index e067cb0..be73cd3 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerTemporaryTableBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerTemporaryTableBuilderTests.cs @@ -7,15 +7,13 @@ public class SqlServerTemporaryTableBuilderTests : UnitTestsBase [Fact] public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() { - Invoking(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) - ) - .Should().Throw(); + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int))) + .Should() + .Throw(); - Invoking(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) - ) - .Should().Throw(); + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int))) + .Should() + .Throw(); } [Fact] @@ -24,20 +22,20 @@ public async Task BuildTemporaryTableAsync_NameIsNullOrEmptyOrWhitespace_ShouldT await Invoking(() => this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) ) - .Should().ThrowAsync(); + .Should() + .ThrowAsync(); await Invoking(() => this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) ) - .Should().ThrowAsync(); + .Should() + .ThrowAsync(); } [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - new SqlServerTemporaryTableBuilder(new()) - ); + ArgumentNullGuardVerifier.Verify(() => new SqlServerTemporaryTableBuilder(new())); ArgumentNullGuardVerifier.Verify(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqliteConfigurationExtensionsTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqliteConfigurationExtensionsTests.cs index 7f2392a..0767d2f 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqliteConfigurationExtensionsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqliteConfigurationExtensionsTests.cs @@ -21,4 +21,4 @@ public void UseSqlServer_ShouldRegisterSqlServerAdapter() adapter.Should().NotBeNull(); adapter.Should().BeOfType(); } -} \ No newline at end of file +} diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteConfigurationExtensionsTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteConfigurationExtensionsTests.cs index 03e18d9..92453a6 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteConfigurationExtensionsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteConfigurationExtensionsTests.cs @@ -22,4 +22,4 @@ public void UseSqlite_ShouldRegisterSqliteAdapter() adapter.Should().NotBeNull(); adapter.Should().BeOfType(); } -} \ No newline at end of file +} diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteDatabaseAdapterTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteDatabaseAdapterTests.cs index 6db13aa..0fc96a1 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteDatabaseAdapterTests.cs @@ -13,11 +13,9 @@ public void BindParameterValue_BytesValue_ShouldSetDbTypeAndValue() this.adapter.BindParameterValue(parameter, value); - parameter.DbType - .Should().Be(DbType.Binary); + parameter.DbType.Should().Be(DbType.Binary); - parameter.Value - .Should().Be(value); + parameter.Value.Should().Be(value); } [Fact] @@ -29,11 +27,9 @@ public void BindParameterValue_DateTimeValue_ShouldSetDbTypeAndValue() this.adapter.BindParameterValue(parameter, value); - parameter.DbType - .Should().Be(DbType.DateTime); + parameter.DbType.Should().Be(DbType.DateTime); - parameter.Value - .Should().Be(value); + parameter.Value.Should().Be(value); } [Fact] @@ -47,11 +43,9 @@ public void BindParameterValue_EnumValue_EnumSerializationModeIsIntegers_ShouldB this.adapter.BindParameterValue(parameter, enumValue); - parameter.DbType - .Should().Be(DbType.Int32); + parameter.DbType.Should().Be(DbType.Int32); - parameter.Value - .Should().Be((int)enumValue); + parameter.Value.Should().Be((int)enumValue); } [Fact] @@ -65,11 +59,9 @@ public void BindParameterValue_EnumValue_EnumSerializationModeIsStrings_ShouldBi this.adapter.BindParameterValue(parameter, enumValue); - parameter.DbType - .Should().Be(DbType.String); + parameter.DbType.Should().Be(DbType.String); - parameter.Value - .Should().Be(enumValue.ToString()); + parameter.Value.Should().Be(enumValue.ToString()); } [Fact] @@ -81,34 +73,30 @@ public void BindParameterValue_ShouldSetValue() this.adapter.BindParameterValue(parameter, value); - parameter.Value - .Should().Be(value); + parameter.Value.Should().Be(value); } [Fact] public void EntityManipulator_ShouldReturnManipulator() => - this.adapter.EntityManipulator - .Should().BeOfType(); + this.adapter.EntityManipulator.Should().BeOfType(); [Fact] public void FormatParameterName_ShouldFormatParameterName() => - this.adapter.FormatParameterName("Param1") - .Should().Be("@Param1"); + this.adapter.FormatParameterName("Param1").Should().Be("@Param1"); [Fact] public void GetDataType_EnumType_EnumSerializationModeIsInteger_ShouldReturnInteger() { - this.adapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Integers) - .Should().Be("INTEGER"); + this.adapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Integers).Should().Be("INTEGER"); - this.adapter.GetDataType(typeof(TestEnum?), EnumSerializationMode.Integers) - .Should().Be("INTEGER"); + this.adapter.GetDataType(typeof(TestEnum?), EnumSerializationMode.Integers).Should().Be("INTEGER"); } [Fact] public void GetDataType_EnumType_EnumSerializationModeIsNotSupported_ShouldThrow() => Invoking(() => this.adapter.GetDataType(typeof(TestEnum), (EnumSerializationMode)999)) - .Should().Throw() + .Should() + .Throw() .WithMessage( $"The {nameof(EnumSerializationMode)} '999' ({typeof(EnumSerializationMode)}) is not supported.*" ); @@ -116,11 +104,9 @@ public void GetDataType_EnumType_EnumSerializationModeIsNotSupported_ShouldThrow [Fact] public void GetDataType_EnumType_EnumSerializationModeIsString_ShouldReturnText() { - this.adapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Strings) - .Should().Be("TEXT"); + this.adapter.GetDataType(typeof(TestEnum), EnumSerializationMode.Strings).Should().Be("TEXT"); - this.adapter.GetDataType(typeof(TestEnum?), EnumSerializationMode.Strings) - .Should().Be("TEXT"); + this.adapter.GetDataType(typeof(TestEnum?), EnumSerializationMode.Strings).Should().Be("TEXT"); } [Theory] @@ -157,50 +143,42 @@ public void GetDataType_EnumType_EnumSerializationModeIsString_ShouldReturnText( [InlineData(typeof(TimeSpan?), "TEXT")] [InlineData(typeof(TimeSpan), "TEXT")] public void GetDataType_SupportedTypeType_ShouldReturnSqliteDataType(Type type, string expectedResult) => - this.adapter.GetDataType(type, EnumSerializationMode.Strings) - .Should().Be(expectedResult); + this.adapter.GetDataType(type, EnumSerializationMode.Strings).Should().Be(expectedResult); [Fact] public void GetDataType_UnsupportedType_ShouldThrow() => Invoking(() => this.adapter.GetDataType(typeof(Entity), EnumSerializationMode.Strings)) - .Should().Throw() + .Should() + .Throw() .WithMessage($"Could not map the type {typeof(Entity)} to an SQLite data type.*"); [Fact] public void QuoteIdentifier_ShouldQuoteIdentifier() => - this.adapter.QuoteIdentifier("MyTable") - .Should().Be("\"MyTable\""); + this.adapter.QuoteIdentifier("MyTable").Should().Be("\"MyTable\""); [Fact] public void QuoteTemporaryTableName_ShouldQuoteTableName() => - this.adapter.QuoteTemporaryTableName("TempTable", this.MockDbConnection) - .Should().Be("temp.\"TempTable\""); + this.adapter.QuoteTemporaryTableName("TempTable", this.MockDbConnection).Should().Be("temp.\"TempTable\""); [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - this.adapter.BindParameterValue(Substitute.For(), null) - ); + ArgumentNullGuardVerifier.Verify(() => this.adapter.BindParameterValue(Substitute.For(), null)); ArgumentNullGuardVerifier.Verify(() => this.adapter.WasSqlStatementCancelledByCancellationToken(new(), CancellationToken.None) ); - ArgumentNullGuardVerifier.Verify(() => - this.adapter.GetDataType(typeof(int), EnumSerializationMode.Integers) - ); + ArgumentNullGuardVerifier.Verify(() => this.adapter.GetDataType(typeof(int), EnumSerializationMode.Integers)); } [Fact] public void TemporaryTableBuilder_ShouldReturnBuilder() => - this.adapter.TemporaryTableBuilder - .Should().BeOfType(); + this.adapter.TemporaryTableBuilder.Should().BeOfType(); [Fact] public void WasSqlStatementCancelledByCancellationToken_ShouldAlwaysReturnFalse() => - this.adapter.WasSqlStatementCancelledByCancellationToken(new(), CancellationToken.None) - .Should().BeFalse(); + this.adapter.WasSqlStatementCancelledByCancellationToken(new(), CancellationToken.None).Should().BeFalse(); private readonly SqliteDatabaseAdapter adapter = new(); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteTemporaryTableBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteTemporaryTableBuilderTests.cs index 4dda894..7e57b9c 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteTemporaryTableBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteTemporaryTableBuilderTests.cs @@ -7,15 +7,13 @@ public class SqliteTemporaryTableBuilderTests : UnitTestsBase [Fact] public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() { - Invoking(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) - ) - .Should().Throw(); + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int))) + .Should() + .Throw(); - Invoking(() => - this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) - ) - .Should().Throw(); + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int))) + .Should() + .Throw(); } [Fact] @@ -24,20 +22,20 @@ public async Task BuildTemporaryTableAsync_NameIsNullOrEmptyOrWhitespace_ShouldT await Invoking(() => this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) ) - .Should().ThrowAsync(); + .Should() + .ThrowAsync(); await Invoking(() => this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) ) - .Should().ThrowAsync(); + .Should() + .ThrowAsync(); } [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - new SqliteTemporaryTableBuilder(new()) - ); + ArgumentNullGuardVerifier.Verify(() => new SqliteTemporaryTableBuilder(new())); ArgumentNullGuardVerifier.Verify(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/TemporaryTableDisposerTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/TemporaryTableDisposerTests.cs index d26d06e..16de010 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/TemporaryTableDisposerTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/TemporaryTableDisposerTests.cs @@ -65,8 +65,6 @@ public void ShouldGuardAgainstNullArguments() Action dropTableFunction = () => { }; Func dropTableAsyncFunction = () => ValueTask.CompletedTask; - ArgumentNullGuardVerifier.Verify(() => - new TemporaryTableDisposer(dropTableFunction, dropTableAsyncFunction) - ); + ArgumentNullGuardVerifier.Verify(() => new TemporaryTableDisposer(dropTableFunction, dropTableAsyncFunction)); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandBuilderTests.cs index 0c30f11..f3355b3 100644 --- a/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandBuilderTests.cs @@ -42,36 +42,23 @@ public async Task BuildDbCommand_Code_Parameters_ShouldStoreCodeAndParameters(bo ("Parameter3", "Value3") ); - var (command, _) = await CallApi( - useAsyncApi, - statement, - this.MockDatabaseAdapter, - this.MockDbConnection - ); + var (command, _) = await CallApi(useAsyncApi, statement, this.MockDatabaseAdapter, this.MockDbConnection); - command.CommandText - .Should().Be("Code"); + command.CommandText.Should().Be("Code"); - command.Parameters.Count - .Should().Be(3); + command.Parameters.Count.Should().Be(3); - command.Parameters[0].ParameterName - .Should().Be("Parameter1"); + command.Parameters[0].ParameterName.Should().Be("Parameter1"); - command.Parameters[0].Value - .Should().Be("Value1"); + command.Parameters[0].Value.Should().Be("Value1"); - command.Parameters[1].ParameterName - .Should().Be("Parameter2"); + command.Parameters[1].ParameterName.Should().Be("Parameter2"); - command.Parameters[1].Value - .Should().Be("Value2"); + command.Parameters[1].Value.Should().Be("Value2"); - command.Parameters[2].ParameterName - .Should().Be("Parameter3"); + command.Parameters[2].ParameterName.Should().Be("Parameter3"); - command.Parameters[2].Value - .Should().Be("Value3"); + command.Parameters[2].Value.Should().Be("Value3"); } [Theory] @@ -89,8 +76,7 @@ public async Task BuildDbCommand_CommandTimeout_ShouldUseCommandTimeout(bool use commandTimeout: timeout ); - command.CommandTimeout - .Should().Be((int)timeout.TotalSeconds); + command.CommandTimeout.Should().Be((int)timeout.TotalSeconds); } [Theory] @@ -106,8 +92,7 @@ public async Task BuildDbCommand_CommandType_ShouldUseCommandType(bool useAsyncA commandType: CommandType.StoredProcedure ); - command.CommandType - .Should().Be(CommandType.StoredProcedure); + command.CommandType.Should().Be(CommandType.StoredProcedure); } [Theory] @@ -124,20 +109,21 @@ public async Task BuildDbCommand_InterpolatedParameter_DuplicateName_ShouldAppen this.MockDbConnection ); - command.CommandText - .Should().Be("SELECT @Value, @Value2, @Value3, @Value4, @Value5"); + command.CommandText.Should().Be("SELECT @Value, @Value2, @Value3, @Value4, @Value5"); - command.Parameters.OfType().Select(a => a.ParameterName) - .Should().BeEquivalentTo("Value", "Value2", "Value3", "Value4", "Value5"); + command + .Parameters.OfType() + .Select(a => a.ParameterName) + .Should() + .BeEquivalentTo("Value", "Value2", "Value3", "Value4", "Value5"); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - BuildDbCommand_InterpolatedParameter_EnumValue_EnumSerializationModeIsIntegers_ShouldSerializeEnumToInteger( - bool useAsyncApi - ) + public async Task BuildDbCommand_InterpolatedParameter_EnumValue_EnumSerializationModeIsIntegers_ShouldSerializeEnumToInteger( + bool useAsyncApi + ) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Integers; @@ -150,23 +136,19 @@ bool useAsyncApi this.MockDbConnection ); - command.Parameters.Count - .Should().Be(1); + command.Parameters.Count.Should().Be(1); - command.Parameters[0].ParameterName - .Should().Be("EnumValue"); + command.Parameters[0].ParameterName.Should().Be("EnumValue"); - command.Parameters[0].Value - .Should().Be((int)enumValue); + command.Parameters[0].Value.Should().Be((int)enumValue); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - BuildDbCommand_InterpolatedParameter_EnumValue_EnumSerializationModeIsStrings_ShouldSerializeEnumToString( - bool useAsyncApi - ) + public async Task BuildDbCommand_InterpolatedParameter_EnumValue_EnumSerializationModeIsStrings_ShouldSerializeEnumToString( + bool useAsyncApi + ) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Strings; @@ -179,14 +161,11 @@ bool useAsyncApi this.MockDbConnection ); - command.Parameters.Count - .Should().Be(1); + command.Parameters.Count.Should().Be(1); - command.Parameters[0].ParameterName - .Should().Be("EnumValue"); + command.Parameters[0].ParameterName.Should().Be("EnumValue"); - command.Parameters[0].Value - .Should().Be(enumValue.ToString()); + command.Parameters[0].Value.Should().Be(enumValue.ToString()); } [Theory] @@ -206,35 +185,25 @@ public async Task BuildDbCommand_InterpolatedParameter_ShouldHandleNullAndNonNul this.MockDbConnection ); - command.Parameters.Count - .Should().Be(4); + command.Parameters.Count.Should().Be(4); - command.CommandText - .Should().Be("SELECT @Id1, @Id2, @Value1, @Value2"); + command.CommandText.Should().Be("SELECT @Id1, @Id2, @Value1, @Value2"); - command.Parameters[0].ParameterName - .Should().Be("Id1"); + command.Parameters[0].ParameterName.Should().Be("Id1"); - command.Parameters[0].Value - .Should().Be(id1); + command.Parameters[0].Value.Should().Be(id1); - command.Parameters[1].ParameterName - .Should().Be("Id2"); + command.Parameters[1].ParameterName.Should().Be("Id2"); - command.Parameters[1].Value - .Should().Be(DBNull.Value); + command.Parameters[1].Value.Should().Be(DBNull.Value); - command.Parameters[2].ParameterName - .Should().Be("Value1"); + command.Parameters[2].ParameterName.Should().Be("Value1"); - command.Parameters[2].Value - .Should().Be(value1); + command.Parameters[2].Value.Should().Be(value1); - command.Parameters[3].ParameterName - .Should().Be("Value2"); + command.Parameters[3].ParameterName.Should().Be("Value2"); - command.Parameters[3].Value - .Should().Be(DBNull.Value); + command.Parameters[3].Value.Should().Be(DBNull.Value); } [Theory] @@ -256,19 +225,20 @@ bool useAsyncApi var (command, _) = await CallApi( useAsyncApi, $""" - SELECT {Parameter(productId)}, - {Parameter(GetProductId())}, - {Parameter(GetProductIdByCategory("Shoes"))}, - {Parameter(productIds[1])}, - {Parameter(this.testProductId)}, - {Parameter(new { })} - """, + SELECT {Parameter(productId)}, + {Parameter(GetProductId())}, + {Parameter(GetProductIdByCategory("Shoes"))}, + {Parameter(productIds[1])}, + {Parameter(this.testProductId)}, + {Parameter(new { })} + """, this.MockDatabaseAdapter, this.MockDbConnection ); - command.CommandText - .Should().Be( + command + .CommandText.Should() + .Be( """ SELECT @ProductId, @ProductId2, @@ -279,26 +249,19 @@ bool useAsyncApi """ ); - command.Parameters.Count - .Should().Be(6); + command.Parameters.Count.Should().Be(6); - command.Parameters[0].ParameterName - .Should().Be("ProductId"); + command.Parameters[0].ParameterName.Should().Be("ProductId"); - command.Parameters[1].ParameterName - .Should().Be("ProductId2"); + command.Parameters[1].ParameterName.Should().Be("ProductId2"); - command.Parameters[2].ParameterName - .Should().Be("ProductIdByCategoryShoes"); + command.Parameters[2].ParameterName.Should().Be("ProductIdByCategoryShoes"); - command.Parameters[3].ParameterName - .Should().Be("ProductIds1"); + command.Parameters[3].ParameterName.Should().Be("ProductIds1"); - command.Parameters[4].ParameterName - .Should().Be("TestProductId"); + command.Parameters[4].ParameterName.Should().Be("TestProductId"); - command.Parameters[5].ParameterName - .Should().Be("Parameter_6"); + command.Parameters[5].ParameterName.Should().Be("Parameter_6"); } [Theory] @@ -315,17 +278,13 @@ public async Task BuildDbCommand_InterpolatedParameter_ShouldStoreParameter(bool this.MockDbConnection ); - command.CommandText - .Should().Be("SELECT @Value"); + command.CommandText.Should().Be("SELECT @Value"); - command.Parameters.Count - .Should().Be(1); + command.Parameters.Count.Should().Be(1); - command.Parameters[0].ParameterName - .Should().Be("Value"); + command.Parameters[0].ParameterName.Should().Be("Value"); - command.Parameters[0].Value - .Should().Be(value); + command.Parameters[0].Value.Should().Be(value); } [Theory] @@ -339,82 +298,72 @@ public async Task BuildDbCommand_InterpolatedParameter_ShouldSupportComplexExpre var (command, _) = await CallApi( useAsyncApi, $""" - SELECT {Parameter(baseDiscount * 5 / 3)}, - {Parameter(entityIds.Where(a => a > 5).ToArray()[0])} - """, + SELECT {Parameter(baseDiscount * 5 / 3)}, + {Parameter(entityIds.Where(a => a > 5).ToArray()[0])} + """, this.MockDatabaseAdapter, this.MockDbConnection ); - command.CommandText - .Should().Be( + command + .CommandText.Should() + .Be( """ SELECT @BaseDiscount53, @EntityIdsWhereaa5ToArray0 """ ); - command.Parameters.Count - .Should().Be(2); + command.Parameters.Count.Should().Be(2); - command.Parameters[0].ParameterName - .Should().Be("BaseDiscount53"); + command.Parameters[0].ParameterName.Should().Be("BaseDiscount53"); - command.Parameters[0].Value - .Should().Be(baseDiscount * 5 / 3); + command.Parameters[0].Value.Should().Be(baseDiscount * 5 / 3); - command.Parameters[1].ParameterName - .Should().Be("EntityIdsWhereaa5ToArray0"); + command.Parameters[1].ParameterName.Should().Be("EntityIdsWhereaa5ToArray0"); - command.Parameters[1].Value - .Should().Be(entityIds.Where(a => a > 5).ToArray()[0]); + command.Parameters[1].Value.Should().Be(entityIds.Where(a => a > 5).ToArray()[0]); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - BuildDbCommand_InterpolatedTemporaryTable_DatabaseAdapterDoesNotSupportTemporaryTables_ShouldThrow( - bool useAsyncApi - ) + public async Task BuildDbCommand_InterpolatedTemporaryTable_DatabaseAdapterDoesNotSupportTemporaryTables_ShouldThrow( + bool useAsyncApi + ) { var entityIds = Generate.Ids(); this.MockDatabaseAdapter.SupportsTemporaryTables(Arg.Any()).Returns(false); - await Invoking(() => CallApi( + await Invoking(() => + CallApi( useAsyncApi, $"SELECT Value FROM {TemporaryTable(entityIds)}", this.MockDatabaseAdapter, this.MockDbConnection ) ) - .Should().ThrowAsync() + .Should() + .ThrowAsync() .WithMessage( - $"The database adapter {this.MockDatabaseAdapter.GetType()} does not support " + - "(local / session-scoped) temporary tables. Therefore the temporary tables feature of " + - "DbConnectionPlus can not be used with this database." + $"The database adapter {this.MockDatabaseAdapter.GetType()} does not support " + + "(local / session-scoped) temporary tables. Therefore the temporary tables feature of " + + "DbConnectionPlus can not be used with this database." ); - // No temporary table used - should not throw. - await Invoking(() => CallApi( - useAsyncApi, - "SELECT 1", - this.MockDatabaseAdapter, - this.MockDbConnection - ) - ) - .Should().NotThrowAsync(); + await Invoking(() => CallApi(useAsyncApi, "SELECT 1", this.MockDatabaseAdapter, this.MockDbConnection)) + .Should() + .NotThrowAsync(); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - BuildDbCommand_InterpolatedTemporaryTable_ShouldInferTableNameFromValuesExpressionIfPossible( - bool useAsyncApi - ) + public async Task BuildDbCommand_InterpolatedTemporaryTable_ShouldInferTableNameFromValuesExpressionIfPossible( + bool useAsyncApi + ) { var entityIds = Generate.Ids(); static List Get() => Generate.Ids(); @@ -425,60 +374,49 @@ bool useAsyncApi #pragma warning restore IDE0060 // Remove unused parameter #pragma warning restore RCS1163 // Unused parameter - InterpolatedSqlStatement statement = - $""" - SELECT Value FROM {TemporaryTable(entityIds)} - UNION - SELECT Value FROM {TemporaryTable(GetEntityIds())} - UNION - SELECT Value FROM {TemporaryTable(GetEntityIdsByCategory("Shoes"))} - UNION - SELECT Value FROM {TemporaryTable(this.testEntityIds)} - UNION - SELECT Value FROM {TemporaryTable(Get())} - """; + InterpolatedSqlStatement statement = $""" + SELECT Value FROM {TemporaryTable(entityIds)} + UNION + SELECT Value FROM {TemporaryTable(GetEntityIds())} + UNION + SELECT Value FROM {TemporaryTable(GetEntityIdsByCategory("Shoes"))} + UNION + SELECT Value FROM {TemporaryTable(this.testEntityIds)} + UNION + SELECT Value FROM {TemporaryTable(Get())} + """; - var (command, _) = await CallApi( - useAsyncApi, - statement, - this.MockDatabaseAdapter, - this.MockDbConnection - ); + var (command, _) = await CallApi(useAsyncApi, statement, this.MockDatabaseAdapter, this.MockDbConnection); var temporaryTables = statement.TemporaryTables; - temporaryTables - .Should().HaveCount(5); + temporaryTables.Should().HaveCount(5); - command.CommandText - .Should().Be( + command + .CommandText.Should() + .Be( $""" - SELECT Value FROM [#{temporaryTables[0].Name}] - UNION - SELECT Value FROM [#{temporaryTables[1].Name}] - UNION - SELECT Value FROM [#{temporaryTables[2].Name}] - UNION - SELECT Value FROM [#{temporaryTables[3].Name}] - UNION - SELECT Value FROM [#{temporaryTables[4].Name}] - """ + SELECT Value FROM [#{temporaryTables[0].Name}] + UNION + SELECT Value FROM [#{temporaryTables[1].Name}] + UNION + SELECT Value FROM [#{temporaryTables[2].Name}] + UNION + SELECT Value FROM [#{temporaryTables[3].Name}] + UNION + SELECT Value FROM [#{temporaryTables[4].Name}] + """ ); - temporaryTables[0].Name - .Should().StartWith("EntityIds_"); + temporaryTables[0].Name.Should().StartWith("EntityIds_"); - temporaryTables[1].Name - .Should().StartWith("EntityIds_"); + temporaryTables[1].Name.Should().StartWith("EntityIds_"); - temporaryTables[2].Name - .Should().StartWith("EntityIdsByCategoryShoes_"); + temporaryTables[2].Name.Should().StartWith("EntityIdsByCategoryShoes_"); - temporaryTables[3].Name - .Should().StartWith("TestEntityIds_"); + temporaryTables[3].Name.Should().StartWith("TestEntityIds_"); - temporaryTables[4].Name - .Should().StartWith("Values_"); + temporaryTables[4].Name.Should().StartWith("Values_"); } [Theory] @@ -489,54 +427,42 @@ public async Task BuildDbCommand_InterpolatedTemporaryTable_ShouldStoreTemporary var entities = Generate.Multiple(); var entityIds = Generate.Ids(); - InterpolatedSqlStatement statement = - $""" - SELECT Id - FROM {TemporaryTable(entities)} Entities - WHERE Entities.Id IN (SELECT Value FROM {TemporaryTable(entityIds)}) - """; + InterpolatedSqlStatement statement = $""" + SELECT Id + FROM {TemporaryTable(entities)} Entities + WHERE Entities.Id IN (SELECT Value FROM {TemporaryTable(entityIds)}) + """; - var (command, _) = await CallApi( - useAsyncApi, - statement, - this.MockDatabaseAdapter, - this.MockDbConnection - ); + var (command, _) = await CallApi(useAsyncApi, statement, this.MockDatabaseAdapter, this.MockDbConnection); var temporaryTables = statement.TemporaryTables; - temporaryTables - .Should().HaveCount(2); + temporaryTables.Should().HaveCount(2); var table1 = temporaryTables[0]; - table1.Name - .Should().StartWith("Entities_"); + table1.Name.Should().StartWith("Entities_"); - table1.Values - .Should().Be(entities); + table1.Values.Should().Be(entities); - table1.ValuesType - .Should().Be(typeof(Entity)); + table1.ValuesType.Should().Be(typeof(Entity)); var table2 = temporaryTables[1]; - table2.Name - .Should().StartWith("EntityIds_"); + table2.Name.Should().StartWith("EntityIds_"); - table2.Values - .Should().BeEquivalentTo(entityIds); + table2.Values.Should().BeEquivalentTo(entityIds); - table2.ValuesType - .Should().Be(typeof(long)); + table2.ValuesType.Should().Be(typeof(long)); - command.CommandText - .Should().Be( + command + .CommandText.Should() + .Be( $""" - SELECT Id - FROM [#{table1.Name}] Entities - WHERE Entities.Id IN (SELECT Value FROM [#{table2.Name}]) - """ + SELECT Id + FROM [#{table1.Name}] Entities + WHERE Entities.Id IN (SELECT Value FROM [#{table2.Name}]) + """ ); } @@ -556,98 +482,65 @@ public async Task BuildDbCommand_MultipleInterpolatedParameters_ShouldStoreParam this.MockDbConnection ); - command.CommandText - .Should() - .Be("SELECT @Value1, @Value2, @Value3"); + command.CommandText.Should().Be("SELECT @Value1, @Value2, @Value3"); - command.Parameters.Count - .Should().Be(3); + command.Parameters.Count.Should().Be(3); - command.Parameters[0].ParameterName - .Should().Be("Value1"); + command.Parameters[0].ParameterName.Should().Be("Value1"); - command.Parameters[0].Value - .Should().Be(value1); + command.Parameters[0].Value.Should().Be(value1); - command.Parameters[1].ParameterName - .Should().Be("Value2"); + command.Parameters[1].ParameterName.Should().Be("Value2"); - command.Parameters[1].Value - .Should().Be(value2); + command.Parameters[1].Value.Should().Be(value2); - command.Parameters[2].ParameterName - .Should().Be("Value3"); + command.Parameters[2].ParameterName.Should().Be("Value3"); - command.Parameters[2].Value - .Should().Be(value3); + command.Parameters[2].Value.Should().Be(value3); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - BuildDbCommand_Parameter_EnumValue_EnumSerializationModeIsIntegers_ShouldSerializeEnumToInteger( - bool useAsyncApi - ) + public async Task BuildDbCommand_Parameter_EnumValue_EnumSerializationModeIsIntegers_ShouldSerializeEnumToInteger( + bool useAsyncApi + ) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Integers; var enumValue = Generate.Single(); - var statement = new InterpolatedSqlStatement( - "Code", - ("Parameter1", enumValue) - ); + var statement = new InterpolatedSqlStatement("Code", ("Parameter1", enumValue)); - var (command, _) = await CallApi( - useAsyncApi, - statement, - this.MockDatabaseAdapter, - this.MockDbConnection - ); + var (command, _) = await CallApi(useAsyncApi, statement, this.MockDatabaseAdapter, this.MockDbConnection); - command.Parameters.Count - .Should().Be(1); + command.Parameters.Count.Should().Be(1); - command.Parameters[0].ParameterName - .Should().Be("Parameter1"); + command.Parameters[0].ParameterName.Should().Be("Parameter1"); - command.Parameters[0].Value - .Should().Be((int)enumValue); + command.Parameters[0].Value.Should().Be((int)enumValue); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task - BuildDbCommand_Parameter_EnumValue_EnumSerializationModeIsStrings_ShouldSerializeEnumToString( - bool useAsyncApi - ) + public async Task BuildDbCommand_Parameter_EnumValue_EnumSerializationModeIsStrings_ShouldSerializeEnumToString( + bool useAsyncApi + ) { DbConnectionPlusConfiguration.Instance.EnumSerializationMode = EnumSerializationMode.Strings; var enumValue = Generate.Single(); - var statement = new InterpolatedSqlStatement( - "Code", - ("Parameter1", enumValue) - ); + var statement = new InterpolatedSqlStatement("Code", ("Parameter1", enumValue)); - var (command, _) = await CallApi( - useAsyncApi, - statement, - this.MockDatabaseAdapter, - this.MockDbConnection - ); + var (command, _) = await CallApi(useAsyncApi, statement, this.MockDatabaseAdapter, this.MockDbConnection); - command.Parameters.Count - .Should().Be(1); + command.Parameters.Count.Should().Be(1); - command.Parameters[0].ParameterName - .Should().Be("Parameter1"); + command.Parameters[0].ParameterName.Should().Be("Parameter1"); - command.Parameters[0].Value - .Should().Be(enumValue.ToString()); + command.Parameters[0].Value.Should().Be(enumValue.ToString()); } [Theory] @@ -657,13 +550,12 @@ public async Task BuildDbCommand_ShouldFormatAndStoreLiteral(bool useAsyncApi) { var (command, _) = await CallApi( useAsyncApi, - $"SELECT {123.45,10:N2}, {123.45,-10:N2}", + $"SELECT {123.45, 10:N2}, {123.45, -10:N2}", this.MockDatabaseAdapter, this.MockDbConnection ); - command.CommandText - .Should().Be("SELECT 123.45, 123.45 "); + command.CommandText.Should().Be("SELECT 123.45, 123.45 "); } [Theory] @@ -678,8 +570,7 @@ public async Task BuildDbCommand_ShouldReturnCommandDisposer(bool useAsyncApi) this.MockDbConnection ); - commandDisposer - .Should().NotBeNull(); + commandDisposer.Should().NotBeNull(); } [Theory] @@ -687,15 +578,9 @@ public async Task BuildDbCommand_ShouldReturnCommandDisposer(bool useAsyncApi) [InlineData(true)] public async Task BuildDbCommand_ShouldStoreLiteral(bool useAsyncApi) { - var (command, _) = await CallApi( - useAsyncApi, - "SELECT 1", - this.MockDatabaseAdapter, - this.MockDbConnection - ); + var (command, _) = await CallApi(useAsyncApi, "SELECT 1", this.MockDatabaseAdapter, this.MockDbConnection); - command.CommandText - .Should().Be("SELECT 1"); + command.CommandText.Should().Be("SELECT 1"); } [Theory] @@ -713,8 +598,7 @@ public async Task BuildDbCommand_Transaction_ShouldUseTransaction(bool useAsyncA transaction ); - command.Transaction - .Should().BeSameAs(transaction); + command.Transaction.Should().BeSameAs(transaction); } private static Task<(DbCommand, DbCommandDisposer)> CallApi( diff --git a/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandDisposerTests.cs b/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandDisposerTests.cs index 613f6dd..f191f30 100644 --- a/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandDisposerTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandDisposerTests.cs @@ -12,8 +12,10 @@ public void Dispose_AlreadyDisposed_ShouldNotDisposeCommandResourcesAgain() { using var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; - var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(this.MockDbCommand, cancellationToken); + var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation( + this.MockDbCommand, + cancellationToken + ); var dropTableFunction1 = Substitute.For(); var dropTableAsyncFunction1 = Substitute.For>(); @@ -24,7 +26,7 @@ public void Dispose_AlreadyDisposed_ShouldNotDisposeCommandResourcesAgain() var temporaryTableDisposers = new[] { new TemporaryTableDisposer(dropTableFunction1, dropTableAsyncFunction1), - new TemporaryTableDisposer(dropTableFunction2, dropTableAsyncFunction2) + new TemporaryTableDisposer(dropTableFunction2, dropTableAsyncFunction2), }; var disposer = new DbCommandDisposer( @@ -47,8 +49,10 @@ public void Dispose_ShouldDisposeCommandResources() { using var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; - var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(this.MockDbCommand, cancellationToken); + var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation( + this.MockDbCommand, + cancellationToken + ); var dropTableFunction1 = Substitute.For(); var dropTableAsyncFunction1 = Substitute.For>(); @@ -59,7 +63,7 @@ public void Dispose_ShouldDisposeCommandResources() var temporaryTableDisposers = new[] { new TemporaryTableDisposer(dropTableFunction1, dropTableAsyncFunction1), - new TemporaryTableDisposer(dropTableFunction2, dropTableAsyncFunction2) + new TemporaryTableDisposer(dropTableFunction2, dropTableAsyncFunction2), }; var disposer = new DbCommandDisposer( @@ -84,8 +88,10 @@ public async Task DisposeAsync_AlreadyDisposed_ShouldNotDisposeCommandResourcesA { using var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; - var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(this.MockDbCommand, cancellationToken); + var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation( + this.MockDbCommand, + cancellationToken + ); var dropTableFunction1 = Substitute.For(); var dropTableAsyncFunction1 = Substitute.For>(); @@ -96,7 +102,7 @@ public async Task DisposeAsync_AlreadyDisposed_ShouldNotDisposeCommandResourcesA var temporaryTableDisposers = new[] { new TemporaryTableDisposer(dropTableFunction1, dropTableAsyncFunction1), - new TemporaryTableDisposer(dropTableFunction2, dropTableAsyncFunction2) + new TemporaryTableDisposer(dropTableFunction2, dropTableAsyncFunction2), }; var disposer = new DbCommandDisposer( @@ -119,8 +125,10 @@ public async Task DisposeAsync_ShouldDisposeCommandResourcesAsync() { using var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; - var cancellationTokenRegistration = - DbCommandHelper.RegisterDbCommandCancellation(this.MockDbCommand, cancellationToken); + var cancellationTokenRegistration = DbCommandHelper.RegisterDbCommandCancellation( + this.MockDbCommand, + cancellationToken + ); var dropTableFunction1 = Substitute.For(); var dropTableAsyncFunction1 = Substitute.For>(); @@ -131,7 +139,7 @@ public async Task DisposeAsync_ShouldDisposeCommandResourcesAsync() var temporaryTableDisposers = new[] { new TemporaryTableDisposer(dropTableFunction1, dropTableAsyncFunction1), - new TemporaryTableDisposer(dropTableFunction2, dropTableAsyncFunction2) + new TemporaryTableDisposer(dropTableFunction2, dropTableAsyncFunction2), }; var disposer = new DbCommandDisposer( @@ -156,11 +164,8 @@ public void ShouldGuardAgainstNullArguments() { TemporaryTableDisposer[] temporaryTableDisposers = []; - ArgumentNullGuardVerifier.Verify(() => new DbCommandDisposer( - this.MockDbCommand, - temporaryTableDisposers, - default - ) + ArgumentNullGuardVerifier.Verify(() => + new DbCommandDisposer(this.MockDbCommand, temporaryTableDisposers, default) ); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandHelperTests.cs b/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandHelperTests.cs index f4e9eca..5158d39 100644 --- a/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandHelperTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandHelperTests.cs @@ -12,11 +12,9 @@ public void RegisterDbCommandCancellation_CancellationToken_ShouldRegister() var registration = DbCommandHelper.RegisterDbCommandCancellation(this.MockDbCommand, cancellationToken); - registration - .Should().NotBe(default(CancellationTokenRegistration)); + registration.Should().NotBe(default(CancellationTokenRegistration)); - registration.Token - .Should().Be(cancellationToken); + registration.Token.Should().Be(cancellationToken); } [Fact] @@ -24,11 +22,9 @@ public void RegisterDbCommandCancellation_NoneCancellationToken_ShouldNotRegiste { var registration = DbCommandHelper.RegisterDbCommandCancellation(this.MockDbCommand, CancellationToken.None); - registration - .Should().Be(default(CancellationTokenRegistration)); + registration.Should().Be(default(CancellationTokenRegistration)); - registration.Token - .Should().Be(CancellationToken.None); + registration.Token.Should().Be(CancellationToken.None); } [Fact] diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ConfigurationTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ConfigurationTests.cs index 3dce9a7..16c4161 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ConfigurationTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ConfigurationTests.cs @@ -8,113 +8,114 @@ public void Configure_ShouldConfigureDbConnectionPlus() InterceptDbCommand interceptDbCommand = (_, _) => { }; Configure(config => - { - config.EnumSerializationMode = EnumSerializationMode.Integers; - config.InterceptDbCommand = interceptDbCommand; - - config.Entity() - .ToTable("MappingTestEntity"); - - config.Entity() - .Property(a => a.Computed_) - .HasColumnName("Computed") - .IsComputed(); - - config.Entity() - .Property(a => a.ConcurrencyToken_) - .HasColumnName("ConcurrencyToken") - .IsConcurrencyToken(); - - config.Entity() - .Property(a => a.Identity_) - .HasColumnName("Identity") - .IsIdentity(); - - config.Entity() - .Property(a => a.Key1_) - .HasColumnName("Key1") - .IsKey(); - - config.Entity() - .Property(a => a.Key2_) - .HasColumnName("Key2") - .IsKey(); - - config.Entity() - .Property(a => a.Value_) - .HasColumnName("Value"); - - config.Entity() - .Property(a => a.NotMapped) - .IsIgnored(); - - config.Entity() - .Property(a => a.RowVersion_) - .HasColumnName("RowVersion") - .IsRowVersion(); - } - ); - - DbConnectionPlusConfiguration.Instance.EnumSerializationMode - .Should().Be(EnumSerializationMode.Integers); - - DbConnectionPlusConfiguration.Instance.InterceptDbCommand - .Should().Be(interceptDbCommand); + { + config.EnumSerializationMode = EnumSerializationMode.Integers; + config.InterceptDbCommand = interceptDbCommand; + + config.Entity().ToTable("MappingTestEntity"); + + config + .Entity() + .Property(a => a.Computed_) + .HasColumnName("Computed") + .IsComputed(); + + config + .Entity() + .Property(a => a.ConcurrencyToken_) + .HasColumnName("ConcurrencyToken") + .IsConcurrencyToken(); + + config + .Entity() + .Property(a => a.Identity_) + .HasColumnName("Identity") + .IsIdentity(); + + config.Entity().Property(a => a.Key1_).HasColumnName("Key1").IsKey(); + + config.Entity().Property(a => a.Key2_).HasColumnName("Key2").IsKey(); + + config.Entity().Property(a => a.Value_).HasColumnName("Value"); + + config.Entity().Property(a => a.NotMapped).IsIgnored(); + + config + .Entity() + .Property(a => a.RowVersion_) + .HasColumnName("RowVersion") + .IsRowVersion(); + }); + + DbConnectionPlusConfiguration.Instance.EnumSerializationMode.Should().Be(EnumSerializationMode.Integers); + + DbConnectionPlusConfiguration.Instance.InterceptDbCommand.Should().Be(interceptDbCommand); var entityTypeBuilders = DbConnectionPlusConfiguration.Instance.GetEntityTypeBuilders(); - entityTypeBuilders - .Should().HaveCount(1); + entityTypeBuilders.Should().HaveCount(1); - entityTypeBuilders - .Should().ContainKeys( - typeof(MappingTestEntityFluentApi) - ); + entityTypeBuilders.Should().ContainKeys(typeof(MappingTestEntityFluentApi)); - entityTypeBuilders[typeof(MappingTestEntityFluentApi)].TableName - .Should().Be("MappingTestEntity"); + entityTypeBuilders[typeof(MappingTestEntityFluentApi)].TableName.Should().Be("MappingTestEntity"); - entityTypeBuilders[typeof(MappingTestEntityFluentApi)].PropertyBuilders["Computed_"].ColumnName - .Should().Be("Computed"); + entityTypeBuilders[typeof(MappingTestEntityFluentApi)] + .PropertyBuilders["Computed_"] + .ColumnName.Should() + .Be("Computed"); - entityTypeBuilders[typeof(MappingTestEntityFluentApi)].PropertyBuilders["Computed_"].IsComputed - .Should().BeTrue(); + entityTypeBuilders[typeof(MappingTestEntityFluentApi)] + .PropertyBuilders["Computed_"] + .IsComputed.Should() + .BeTrue(); - entityTypeBuilders[typeof(MappingTestEntityFluentApi)].PropertyBuilders["ConcurrencyToken_"].ColumnName - .Should().Be("ConcurrencyToken"); + entityTypeBuilders[typeof(MappingTestEntityFluentApi)] + .PropertyBuilders["ConcurrencyToken_"] + .ColumnName.Should() + .Be("ConcurrencyToken"); - entityTypeBuilders[typeof(MappingTestEntityFluentApi)].PropertyBuilders["ConcurrencyToken_"].IsConcurrencyToken - .Should().BeTrue(); + entityTypeBuilders[typeof(MappingTestEntityFluentApi)] + .PropertyBuilders["ConcurrencyToken_"] + .IsConcurrencyToken.Should() + .BeTrue(); - entityTypeBuilders[typeof(MappingTestEntityFluentApi)].PropertyBuilders["Identity_"].ColumnName - .Should().Be("Identity"); + entityTypeBuilders[typeof(MappingTestEntityFluentApi)] + .PropertyBuilders["Identity_"] + .ColumnName.Should() + .Be("Identity"); - entityTypeBuilders[typeof(MappingTestEntityFluentApi)].PropertyBuilders["Identity_"].IsIdentity - .Should().BeTrue(); + entityTypeBuilders[typeof(MappingTestEntityFluentApi)] + .PropertyBuilders["Identity_"] + .IsIdentity.Should() + .BeTrue(); - entityTypeBuilders[typeof(MappingTestEntityFluentApi)].PropertyBuilders["Key1_"].ColumnName - .Should().Be("Key1"); + entityTypeBuilders[typeof(MappingTestEntityFluentApi)].PropertyBuilders["Key1_"].ColumnName.Should().Be("Key1"); - entityTypeBuilders[typeof(MappingTestEntityFluentApi)].PropertyBuilders["Key1_"].IsKey - .Should().BeTrue(); + entityTypeBuilders[typeof(MappingTestEntityFluentApi)].PropertyBuilders["Key1_"].IsKey.Should().BeTrue(); - entityTypeBuilders[typeof(MappingTestEntityFluentApi)].PropertyBuilders["Key2_"].ColumnName - .Should().Be("Key2"); + entityTypeBuilders[typeof(MappingTestEntityFluentApi)].PropertyBuilders["Key2_"].ColumnName.Should().Be("Key2"); - entityTypeBuilders[typeof(MappingTestEntityFluentApi)].PropertyBuilders["Key2_"].IsKey - .Should().BeTrue(); + entityTypeBuilders[typeof(MappingTestEntityFluentApi)].PropertyBuilders["Key2_"].IsKey.Should().BeTrue(); - entityTypeBuilders[typeof(MappingTestEntityFluentApi)].PropertyBuilders["Value_"].ColumnName - .Should().Be("Value"); + entityTypeBuilders[typeof(MappingTestEntityFluentApi)] + .PropertyBuilders["Value_"] + .ColumnName.Should() + .Be("Value"); - entityTypeBuilders[typeof(MappingTestEntityFluentApi)].PropertyBuilders["NotMapped"].IsIgnored - .Should().BeTrue(); + entityTypeBuilders[typeof(MappingTestEntityFluentApi)] + .PropertyBuilders["NotMapped"] + .IsIgnored.Should() + .BeTrue(); - entityTypeBuilders[typeof(MappingTestEntityFluentApi)].PropertyBuilders["RowVersion_"].ColumnName - .Should().Be("RowVersion"); + entityTypeBuilders[typeof(MappingTestEntityFluentApi)] + .PropertyBuilders["RowVersion_"] + .ColumnName.Should() + .Be("RowVersion"); - entityTypeBuilders[typeof(MappingTestEntityFluentApi)].PropertyBuilders["RowVersion_"].IsRowVersion - .Should().BeTrue(); + entityTypeBuilders[typeof(MappingTestEntityFluentApi)] + .PropertyBuilders["RowVersion_"] + .IsRowVersion.Should() + .BeTrue(); } [Fact] @@ -123,7 +124,8 @@ public void Configure_ShouldFreezeConfiguration() Configure(configuration => configuration.EnumSerializationMode = EnumSerializationMode.Integers); Invoking(() => Configure(configuration => configuration.EnumSerializationMode = EnumSerializationMode.Strings)) - .Should().Throw() + .Should() + .Throw() .WithMessage("The configuration of DbConnectionPlus is frozen and can no longer be modified."); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.DeleteEntitiesTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.DeleteEntitiesTests.cs index 8adf1c0..67a2171 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.DeleteEntitiesTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.DeleteEntitiesTests.cs @@ -10,22 +10,15 @@ public void DeleteEntities_ShouldCallEntityManipulator() var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.DeleteEntities( - this.MockDbConnection, - entities, - transaction, - cancellationToken - ).Returns(numberOfAffectedRows); + this.MockEntityManipulator.DeleteEntities(this.MockDbConnection, entities, transaction, cancellationToken) + .Returns(numberOfAffectedRows); this.MockDbConnection.DeleteEntities(entities, transaction, cancellationToken) - .Should().Be(numberOfAffectedRows); + .Should() + .Be(numberOfAffectedRows); - this.MockEntityManipulator.Received().DeleteEntities( - this.MockDbConnection, - entities, - transaction, - cancellationToken - ); + this.MockEntityManipulator.Received() + .DeleteEntities(this.MockDbConnection, entities, transaction, cancellationToken); } [Fact] @@ -36,22 +29,16 @@ public async Task DeleteEntitiesAsync_ShouldCallEntityManipulator() var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.DeleteEntitiesAsync( - this.MockDbConnection, - entities, - transaction, - cancellationToken - ).Returns(numberOfAffectedRows); + this.MockEntityManipulator.DeleteEntitiesAsync(this.MockDbConnection, entities, transaction, cancellationToken) + .Returns(numberOfAffectedRows); (await this.MockDbConnection.DeleteEntitiesAsync(entities, transaction, cancellationToken)) - .Should().Be(numberOfAffectedRows); + .Should() + .Be(numberOfAffectedRows); - await this.MockEntityManipulator.Received().DeleteEntitiesAsync( - this.MockDbConnection, - entities, - transaction, - cancellationToken - ); + await this + .MockEntityManipulator.Received() + .DeleteEntitiesAsync(this.MockDbConnection, entities, transaction, cancellationToken); } [Fact] @@ -59,12 +46,8 @@ public void ShouldGuardAgainstNullArguments() { var entities = Generate.Multiple(); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.DeleteEntities(entities) - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.DeleteEntities(entities)); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.DeleteEntitiesAsync(entities) - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.DeleteEntitiesAsync(entities)); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.DeleteEntityTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.DeleteEntityTests.cs index 30bbb7c..94ba8ea 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.DeleteEntityTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.DeleteEntityTests.cs @@ -10,22 +10,13 @@ public void DeleteEntity_ShouldCallEntityManipulator() var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.DeleteEntity( - this.MockDbConnection, - entity, - transaction, - cancellationToken - ).Returns(numberOfAffectedRows); + this.MockEntityManipulator.DeleteEntity(this.MockDbConnection, entity, transaction, cancellationToken) + .Returns(numberOfAffectedRows); - this.MockDbConnection.DeleteEntity(entity, transaction, cancellationToken) - .Should().Be(numberOfAffectedRows); + this.MockDbConnection.DeleteEntity(entity, transaction, cancellationToken).Should().Be(numberOfAffectedRows); - this.MockEntityManipulator.Received().DeleteEntity( - this.MockDbConnection, - entity, - transaction, - cancellationToken - ); + this.MockEntityManipulator.Received() + .DeleteEntity(this.MockDbConnection, entity, transaction, cancellationToken); } [Fact] @@ -36,22 +27,16 @@ public async Task DeleteEntityAsync_ShouldCallEntityManipulator() var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.DeleteEntityAsync( - this.MockDbConnection, - entity, - transaction, - cancellationToken - ).Returns(numberOfAffectedRows); + this.MockEntityManipulator.DeleteEntityAsync(this.MockDbConnection, entity, transaction, cancellationToken) + .Returns(numberOfAffectedRows); (await this.MockDbConnection.DeleteEntityAsync(entity, transaction, cancellationToken)) - .Should().Be(numberOfAffectedRows); + .Should() + .Be(numberOfAffectedRows); - await this.MockEntityManipulator.Received().DeleteEntityAsync( - this.MockDbConnection, - entity, - transaction, - cancellationToken - ); + await this + .MockEntityManipulator.Received() + .DeleteEntityAsync(this.MockDbConnection, entity, transaction, cancellationToken); } [Fact] @@ -59,12 +44,8 @@ public void ShouldGuardAgainstNullArguments() { var entity = Generate.Single(); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.DeleteEntity(entity) - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.DeleteEntity(entity)); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.DeleteEntityAsync(entity) - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.DeleteEntityAsync(entity)); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ExecuteNonQueryTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ExecuteNonQueryTests.cs index 13713df..6a67eab 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ExecuteNonQueryTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ExecuteNonQueryTests.cs @@ -1,35 +1,18 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; -public class DbConnectionExtensions_ExecuteNonQueryTests() : StatementMethodTestsBase( - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.ExecuteNonQueryAsync(sql, transaction, timeout, commandType, cancellationToken), - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.ExecuteNonQuery(sql, transaction, timeout, commandType, cancellationToken) -) +public class DbConnectionExtensions_ExecuteNonQueryTests() + : StatementMethodTestsBase( + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.ExecuteNonQueryAsync(sql, transaction, timeout, commandType, cancellationToken), + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.ExecuteNonQuery(sql, transaction, timeout, commandType, cancellationToken) + ) { [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.ExecuteNonQuery("DELETE FROM Entity") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.ExecuteNonQuery("DELETE FROM Entity")); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.ExecuteNonQueryAsync("DELETE FROM Entity") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.ExecuteNonQueryAsync("DELETE FROM Entity")); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ExecuteReaderTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ExecuteReaderTests.cs index 6b1b585..b883a32 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ExecuteReaderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ExecuteReaderTests.cs @@ -1,42 +1,25 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; -public class DbConnectionExtensions_ExecuteReaderTests() : StatementMethodTestsBase( - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.ExecuteReaderAsync( - sql, - transaction, - timeout, - CommandBehavior.Default, - commandType, - cancellationToken - ), - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.ExecuteReader(sql, transaction, timeout, CommandBehavior.Default, commandType, cancellationToken) -) +public class DbConnectionExtensions_ExecuteReaderTests() + : StatementMethodTestsBase( + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.ExecuteReaderAsync( + sql, + transaction, + timeout, + CommandBehavior.Default, + commandType, + cancellationToken + ), + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.ExecuteReader(sql, transaction, timeout, CommandBehavior.Default, commandType, cancellationToken) + ) { [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.ExecuteReader("SELECT * FROM Entity") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.ExecuteReader("SELECT * FROM Entity")); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.ExecuteReaderAsync("SELECT * FROM Entity") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.ExecuteReaderAsync("SELECT * FROM Entity")); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ExecuteScalarTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ExecuteScalarTests.cs index 24078b0..0dfb217 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ExecuteScalarTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ExecuteScalarTests.cs @@ -1,35 +1,18 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; -public class DbConnectionExtensions_ExecuteScalarTests() : StatementMethodTestsBase( - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.ExecuteScalarAsync(sql, transaction, timeout, commandType, cancellationToken), - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.ExecuteScalar(sql, transaction, timeout, commandType, cancellationToken) -) +public class DbConnectionExtensions_ExecuteScalarTests() + : StatementMethodTestsBase( + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.ExecuteScalarAsync(sql, transaction, timeout, commandType, cancellationToken), + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.ExecuteScalar(sql, transaction, timeout, commandType, cancellationToken) + ) { [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.ExecuteScalar("SELECT 1") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.ExecuteScalar("SELECT 1")); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.ExecuteScalarAsync("SELECT 1") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.ExecuteScalarAsync("SELECT 1")); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ExistsTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ExistsTests.cs index 56cae06..b0828a1 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ExistsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ExistsTests.cs @@ -1,35 +1,18 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; -public class DbConnectionExtensions_ExistsTests() : StatementMethodTestsBase( - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.ExistsAsync(sql, transaction, timeout, commandType, cancellationToken), - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.Exists(sql, transaction, timeout, commandType, cancellationToken) -) +public class DbConnectionExtensions_ExistsTests() + : StatementMethodTestsBase( + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.ExistsAsync(sql, transaction, timeout, commandType, cancellationToken), + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.Exists(sql, transaction, timeout, commandType, cancellationToken) + ) { [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.Exists("SELECT 1") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.Exists("SELECT 1")); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.ExistsAsync("SELECT 1") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.ExistsAsync("SELECT 1")); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.InsertEntitiesTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.InsertEntitiesTests.cs index 1c4c4d5..c7f1ff5 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.InsertEntitiesTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.InsertEntitiesTests.cs @@ -10,22 +10,15 @@ public void InsertEntities_ShouldCallEntityManipulator() var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.InsertEntities( - this.MockDbConnection, - entities, - transaction, - cancellationToken - ).Returns(numberOfAffectedRows); + this.MockEntityManipulator.InsertEntities(this.MockDbConnection, entities, transaction, cancellationToken) + .Returns(numberOfAffectedRows); this.MockDbConnection.InsertEntities(entities, transaction, cancellationToken) - .Should().Be(numberOfAffectedRows); + .Should() + .Be(numberOfAffectedRows); - this.MockEntityManipulator.Received().InsertEntities( - this.MockDbConnection, - entities, - transaction, - cancellationToken - ); + this.MockEntityManipulator.Received() + .InsertEntities(this.MockDbConnection, entities, transaction, cancellationToken); } [Fact] @@ -36,22 +29,16 @@ public async Task InsertEntitiesAsync_ShouldCallEntityManipulator() var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.InsertEntitiesAsync( - this.MockDbConnection, - entities, - transaction, - cancellationToken - ).Returns(numberOfAffectedRows); + this.MockEntityManipulator.InsertEntitiesAsync(this.MockDbConnection, entities, transaction, cancellationToken) + .Returns(numberOfAffectedRows); (await this.MockDbConnection.InsertEntitiesAsync(entities, transaction, cancellationToken)) - .Should().Be(numberOfAffectedRows); + .Should() + .Be(numberOfAffectedRows); - await this.MockEntityManipulator.Received().InsertEntitiesAsync( - this.MockDbConnection, - entities, - transaction, - cancellationToken - ); + await this + .MockEntityManipulator.Received() + .InsertEntitiesAsync(this.MockDbConnection, entities, transaction, cancellationToken); } [Fact] @@ -59,12 +46,8 @@ public void ShouldGuardAgainstNullArguments() { var entities = Generate.Multiple(); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.InsertEntities(entities) - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.InsertEntities(entities)); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.InsertEntitiesAsync(entities) - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.InsertEntitiesAsync(entities)); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.InsertEntityTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.InsertEntityTests.cs index d1386cb..682dd5f 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.InsertEntityTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.InsertEntityTests.cs @@ -10,22 +10,13 @@ public void InsertEntity_ShouldCallEntityManipulator() var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.InsertEntity( - this.MockDbConnection, - entity, - transaction, - cancellationToken - ).Returns(numberOfAffectedRows); + this.MockEntityManipulator.InsertEntity(this.MockDbConnection, entity, transaction, cancellationToken) + .Returns(numberOfAffectedRows); - this.MockDbConnection.InsertEntity(entity, transaction, cancellationToken) - .Should().Be(numberOfAffectedRows); + this.MockDbConnection.InsertEntity(entity, transaction, cancellationToken).Should().Be(numberOfAffectedRows); - this.MockEntityManipulator.Received().InsertEntity( - this.MockDbConnection, - entity, - transaction, - cancellationToken - ); + this.MockEntityManipulator.Received() + .InsertEntity(this.MockDbConnection, entity, transaction, cancellationToken); } [Fact] @@ -36,22 +27,16 @@ public async Task InsertEntityAsync_ShouldCallEntityManipulator() var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.InsertEntityAsync( - this.MockDbConnection, - entity, - transaction, - cancellationToken - ).Returns(numberOfAffectedRows); + this.MockEntityManipulator.InsertEntityAsync(this.MockDbConnection, entity, transaction, cancellationToken) + .Returns(numberOfAffectedRows); (await this.MockDbConnection.InsertEntityAsync(entity, transaction, cancellationToken)) - .Should().Be(numberOfAffectedRows); + .Should() + .Be(numberOfAffectedRows); - await this.MockEntityManipulator.Received().InsertEntityAsync( - this.MockDbConnection, - entity, - transaction, - cancellationToken - ); + await this + .MockEntityManipulator.Received() + .InsertEntityAsync(this.MockDbConnection, entity, transaction, cancellationToken); } [Fact] @@ -59,12 +44,8 @@ public void ShouldGuardAgainstNullArguments() { var entity = Generate.Single(); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.InsertEntity(entity) - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.InsertEntity(entity)); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.InsertEntityAsync(entity) - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.InsertEntityAsync(entity)); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ParameterTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ParameterTests.cs index 1204c56..6c6c284 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ParameterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ParameterTests.cs @@ -14,23 +14,17 @@ public void Parameter_ShouldInferParameterNameFromValueExpressionIfPossible() #pragma warning restore RCS1163 // Unused parameter var productIds = Generate.Ids().ToArray(); - Parameter(productId).InferredName - .Should().Be("ProductId"); + Parameter(productId).InferredName.Should().Be("ProductId"); - Parameter(GetProductId()).InferredName - .Should().Be("ProductId"); + Parameter(GetProductId()).InferredName.Should().Be("ProductId"); - Parameter(GetProductIdByCategory("Shoes")).InferredName - .Should().Be("ProductIdByCategoryShoes"); + Parameter(GetProductIdByCategory("Shoes")).InferredName.Should().Be("ProductIdByCategoryShoes"); - Parameter(productIds[1]).InferredName - .Should().Be("ProductIds1"); + Parameter(productIds[1]).InferredName.Should().Be("ProductIds1"); - Parameter(TestProductId).InferredName - .Should().Be("TestProductId"); + Parameter(TestProductId).InferredName.Should().Be("TestProductId"); - Parameter(new { }).InferredName - .Should().BeNull(); + Parameter(new { }).InferredName.Should().BeNull(); } [Fact] @@ -40,11 +34,9 @@ public void Parameter_ShouldReturnInterpolatedParameter() var interpolatedParameter = Parameter(value); - interpolatedParameter.InferredName - .Should().Be("Value"); + interpolatedParameter.InferredName.Should().Be("Value"); - interpolatedParameter.Value - .Should().Be(value); + interpolatedParameter.Value.Should().Be(value); } [Fact] @@ -53,8 +45,9 @@ public void Parameter_ShouldTruncateInferredParameterName() // ReSharper disable once InconsistentNaming const int longname_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890 = 1; - Parameter(longname_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890).InferredName - .Should().HaveLength(60) + Parameter(longname_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890) + .InferredName.Should() + .HaveLength(60) .And.Be("Longname_1234567890_1234567890_1234567890_1234567890_1234567"); } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOfTTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOfTTests.cs index 7999d59..d6379b5 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOfTTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOfTTests.cs @@ -4,26 +4,13 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; public class DbConnectionExtensions_QueryFirstOfTTests : StatementMethodTestsBase { - public DbConnectionExtensions_QueryFirstOfTTests() : base( - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.QueryFirstAsync(sql, transaction, timeout, commandType, cancellationToken), - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.QueryFirst(sql, transaction, timeout, commandType, cancellationToken) - ) + public DbConnectionExtensions_QueryFirstOfTTests() + : base( + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.QueryFirstAsync(sql, transaction, timeout, commandType, cancellationToken), + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.QueryFirst(sql, transaction, timeout, commandType, cancellationToken) + ) { var mockDbDataReader = Substitute.For(); @@ -34,8 +21,7 @@ public DbConnectionExtensions_QueryFirstOfTTests() : base( mockDbDataReader.Read().Returns(true); mockDbDataReader.ReadAsync(TestContext.Current.CancellationToken).Returns(true); - this.MockDbCommand.ExecuteReader(Arg.Any()) - .Returns(mockDbDataReader); + this.MockDbCommand.ExecuteReader(Arg.Any()).Returns(mockDbDataReader); this.MockDbCommand.ExecuteReaderAsync(Arg.Any(), Arg.Any()) .Returns(mockDbDataReader); @@ -44,12 +30,8 @@ public DbConnectionExtensions_QueryFirstOfTTests() : base( [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.QueryFirst("SELECT * FROM Entity") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.QueryFirst("SELECT * FROM Entity")); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.QueryFirstAsync("SELECT * FROM Entity") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.QueryFirstAsync("SELECT * FROM Entity")); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOrDefaultOfTTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOrDefaultOfTTests.cs index 3a9bd6e..04aacdb 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOrDefaultOfTTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOrDefaultOfTTests.cs @@ -4,26 +4,13 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; public class DbConnectionExtensions_QueryFirstOrDefaultOfTTests : StatementMethodTestsBase { - public DbConnectionExtensions_QueryFirstOrDefaultOfTTests() : base( - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.QueryFirstOrDefaultAsync(sql, transaction, timeout, commandType, cancellationToken), - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.QueryFirstOrDefault(sql, transaction, timeout, commandType, cancellationToken) - ) + public DbConnectionExtensions_QueryFirstOrDefaultOfTTests() + : base( + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.QueryFirstOrDefaultAsync(sql, transaction, timeout, commandType, cancellationToken), + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.QueryFirstOrDefault(sql, transaction, timeout, commandType, cancellationToken) + ) { var mockDbDataReader = Substitute.For(); @@ -34,8 +21,7 @@ public DbConnectionExtensions_QueryFirstOrDefaultOfTTests() : base( mockDbDataReader.Read().Returns(true); mockDbDataReader.ReadAsync(TestContext.Current.CancellationToken).Returns(true); - this.MockDbCommand.ExecuteReader(Arg.Any()) - .Returns(mockDbDataReader); + this.MockDbCommand.ExecuteReader(Arg.Any()).Returns(mockDbDataReader); this.MockDbCommand.ExecuteReaderAsync(Arg.Any(), Arg.Any()) .Returns(mockDbDataReader); diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOrDefaultTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOrDefaultTests.cs index 6e1e87e..1f97b0a 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOrDefaultTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstOrDefaultTests.cs @@ -4,26 +4,13 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; public class DbConnectionExtensions_QueryFirstOrDefaultTests : StatementMethodTestsBase { - public DbConnectionExtensions_QueryFirstOrDefaultTests() : base( - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.QueryFirstOrDefaultAsync(sql, transaction, timeout, commandType, cancellationToken), - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.QueryFirstOrDefault(sql, transaction, timeout, commandType, cancellationToken) - ) + public DbConnectionExtensions_QueryFirstOrDefaultTests() + : base( + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.QueryFirstOrDefaultAsync(sql, transaction, timeout, commandType, cancellationToken), + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.QueryFirstOrDefault(sql, transaction, timeout, commandType, cancellationToken) + ) { var mockDbDataReader = Substitute.For(); @@ -34,8 +21,7 @@ public DbConnectionExtensions_QueryFirstOrDefaultTests() : base( mockDbDataReader.Read().Returns(true); mockDbDataReader.ReadAsync(TestContext.Current.CancellationToken).Returns(true); - this.MockDbCommand.ExecuteReader(Arg.Any()) - .Returns(mockDbDataReader); + this.MockDbCommand.ExecuteReader(Arg.Any()).Returns(mockDbDataReader); this.MockDbCommand.ExecuteReaderAsync(Arg.Any(), Arg.Any()) .Returns(mockDbDataReader); @@ -44,12 +30,8 @@ public DbConnectionExtensions_QueryFirstOrDefaultTests() : base( [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.QueryFirstOrDefault("SELECT * FROM Entity") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.QueryFirstOrDefault("SELECT * FROM Entity")); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.QueryFirstOrDefaultAsync("SELECT * FROM Entity") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.QueryFirstOrDefaultAsync("SELECT * FROM Entity")); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstTests.cs index 3972ad1..3137204 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryFirstTests.cs @@ -4,26 +4,13 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; public class DbConnectionExtensions_QueryFirstTests : StatementMethodTestsBase { - public DbConnectionExtensions_QueryFirstTests() : base( - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.QueryFirstAsync(sql, transaction, timeout, commandType, cancellationToken), - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.QueryFirst(sql, transaction, timeout, commandType, cancellationToken) - ) + public DbConnectionExtensions_QueryFirstTests() + : base( + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.QueryFirstAsync(sql, transaction, timeout, commandType, cancellationToken), + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.QueryFirst(sql, transaction, timeout, commandType, cancellationToken) + ) { var mockDbDataReader = Substitute.For(); @@ -34,8 +21,7 @@ public DbConnectionExtensions_QueryFirstTests() : base( mockDbDataReader.Read().Returns(true); mockDbDataReader.ReadAsync(TestContext.Current.CancellationToken).Returns(true); - this.MockDbCommand.ExecuteReader(Arg.Any()) - .Returns(mockDbDataReader); + this.MockDbCommand.ExecuteReader(Arg.Any()).Returns(mockDbDataReader); this.MockDbCommand.ExecuteReaderAsync(Arg.Any(), Arg.Any()) .Returns(mockDbDataReader); @@ -44,12 +30,8 @@ public DbConnectionExtensions_QueryFirstTests() : base( [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.QueryFirst("SELECT * FROM Entity") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.QueryFirst("SELECT * FROM Entity")); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.QueryFirstAsync("SELECT * FROM Entity") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.QueryFirstAsync("SELECT * FROM Entity")); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryOfTTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryOfTTests.cs index 9dda5eb..98d3d8d 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryOfTTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryOfTTests.cs @@ -6,27 +6,16 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; public class DbConnectionExtensions_QueryOfTTests : StatementMethodTestsBase { - public DbConnectionExtensions_QueryOfTTests() : base( - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.QueryAsync(sql, transaction, timeout, commandType, cancellationToken) - .ToListAsync(TestContext.Current.CancellationToken).AsTask(), - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.Query(sql, transaction, timeout, commandType, cancellationToken).ToList() - ) + public DbConnectionExtensions_QueryOfTTests() + : base( + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection + .QueryAsync(sql, transaction, timeout, commandType, cancellationToken) + .ToListAsync(TestContext.Current.CancellationToken) + .AsTask(), + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.Query(sql, transaction, timeout, commandType, cancellationToken).ToList() + ) { var mockDbDataReader = Substitute.For(); @@ -34,8 +23,7 @@ public DbConnectionExtensions_QueryOfTTests() : base( mockDbDataReader.GetName(0).Returns("Id"); mockDbDataReader.GetFieldType(0).Returns(typeof(long)); - this.MockDbCommand.ExecuteReader(Arg.Any()) - .Returns(mockDbDataReader); + this.MockDbCommand.ExecuteReader(Arg.Any()).Returns(mockDbDataReader); this.MockDbCommand.ExecuteReaderAsync(Arg.Any(), Arg.Any()) .Returns(mockDbDataReader); @@ -44,12 +32,8 @@ public DbConnectionExtensions_QueryOfTTests() : base( [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.Query("SELECT * FROM Entity") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.Query("SELECT * FROM Entity")); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.QueryAsync("SELECT * FROM Entity") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.QueryAsync("SELECT * FROM Entity")); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOfTTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOfTTests.cs index 80cee1c..9569f24 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOfTTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOfTTests.cs @@ -4,26 +4,13 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; public class DbConnectionExtensions_QuerySingleOfTTests : StatementMethodTestsBase { - public DbConnectionExtensions_QuerySingleOfTTests() : base( - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.QuerySingleAsync(sql, transaction, timeout, commandType, cancellationToken), - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.QuerySingle(sql, transaction, timeout, commandType, cancellationToken) - ) + public DbConnectionExtensions_QuerySingleOfTTests() + : base( + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.QuerySingleAsync(sql, transaction, timeout, commandType, cancellationToken), + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.QuerySingle(sql, transaction, timeout, commandType, cancellationToken) + ) { var mockDbDataReader = Substitute.For(); @@ -34,8 +21,7 @@ public DbConnectionExtensions_QuerySingleOfTTests() : base( mockDbDataReader.Read().Returns(true, false); mockDbDataReader.ReadAsync(TestContext.Current.CancellationToken).Returns(true, false); - this.MockDbCommand.ExecuteReader(Arg.Any()) - .Returns(mockDbDataReader); + this.MockDbCommand.ExecuteReader(Arg.Any()).Returns(mockDbDataReader); this.MockDbCommand.ExecuteReaderAsync(Arg.Any(), Arg.Any()) .Returns(mockDbDataReader); @@ -44,12 +30,8 @@ public DbConnectionExtensions_QuerySingleOfTTests() : base( [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.QuerySingle("SELECT * FROM Entity") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.QuerySingle("SELECT * FROM Entity")); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.QuerySingleAsync("SELECT * FROM Entity") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.QuerySingleAsync("SELECT * FROM Entity")); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOrDefaultOfTTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOrDefaultOfTTests.cs index 4b1ac1c..d289a1a 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOrDefaultOfTTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOrDefaultOfTTests.cs @@ -4,26 +4,13 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; public class DbConnectionExtensions_QuerySingleOrDefaultOfTTests : StatementMethodTestsBase { - public DbConnectionExtensions_QuerySingleOrDefaultOfTTests() : base( - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.QuerySingleOrDefaultAsync(sql, transaction, timeout, commandType, cancellationToken), - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.QuerySingleOrDefault(sql, transaction, timeout, commandType, cancellationToken) - ) + public DbConnectionExtensions_QuerySingleOrDefaultOfTTests() + : base( + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.QuerySingleOrDefaultAsync(sql, transaction, timeout, commandType, cancellationToken), + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.QuerySingleOrDefault(sql, transaction, timeout, commandType, cancellationToken) + ) { var mockDbDataReader = Substitute.For(); @@ -34,8 +21,7 @@ public DbConnectionExtensions_QuerySingleOrDefaultOfTTests() : base( mockDbDataReader.Read().Returns(true, false); mockDbDataReader.ReadAsync(TestContext.Current.CancellationToken).Returns(true, false); - this.MockDbCommand.ExecuteReader(Arg.Any()) - .Returns(mockDbDataReader); + this.MockDbCommand.ExecuteReader(Arg.Any()).Returns(mockDbDataReader); this.MockDbCommand.ExecuteReaderAsync(Arg.Any(), Arg.Any()) .Returns(mockDbDataReader); diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOrDefaultTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOrDefaultTests.cs index 4f26643..d80d198 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOrDefaultTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleOrDefaultTests.cs @@ -4,26 +4,13 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; public class DbConnectionExtensions_QuerySingleOrDefaultTests : StatementMethodTestsBase { - public DbConnectionExtensions_QuerySingleOrDefaultTests() : base( - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.QuerySingleOrDefaultAsync(sql, transaction, timeout, commandType, cancellationToken), - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.QuerySingleOrDefault(sql, transaction, timeout, commandType, cancellationToken) - ) + public DbConnectionExtensions_QuerySingleOrDefaultTests() + : base( + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.QuerySingleOrDefaultAsync(sql, transaction, timeout, commandType, cancellationToken), + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.QuerySingleOrDefault(sql, transaction, timeout, commandType, cancellationToken) + ) { var mockDbDataReader = Substitute.For(); @@ -34,8 +21,7 @@ public DbConnectionExtensions_QuerySingleOrDefaultTests() : base( mockDbDataReader.Read().Returns(true, false); mockDbDataReader.ReadAsync(TestContext.Current.CancellationToken).Returns(true, false); - this.MockDbCommand.ExecuteReader(Arg.Any()) - .Returns(mockDbDataReader); + this.MockDbCommand.ExecuteReader(Arg.Any()).Returns(mockDbDataReader); this.MockDbCommand.ExecuteReaderAsync(Arg.Any(), Arg.Any()) .Returns(mockDbDataReader); @@ -44,12 +30,8 @@ public DbConnectionExtensions_QuerySingleOrDefaultTests() : base( [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.QuerySingleOrDefault("SELECT * FROM Entity") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.QuerySingleOrDefault("SELECT * FROM Entity")); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.QuerySingleOrDefaultAsync("SELECT * FROM Entity") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.QuerySingleOrDefaultAsync("SELECT * FROM Entity")); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleTests.cs index 7b60b78..b3d846e 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QuerySingleTests.cs @@ -4,26 +4,13 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; public class DbConnectionExtensions_QuerySingleTests : StatementMethodTestsBase { - public DbConnectionExtensions_QuerySingleTests() : base( - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.QuerySingleAsync(sql, transaction, timeout, commandType, cancellationToken), - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.QuerySingle(sql, transaction, timeout, commandType, cancellationToken) - ) + public DbConnectionExtensions_QuerySingleTests() + : base( + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.QuerySingleAsync(sql, transaction, timeout, commandType, cancellationToken), + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.QuerySingle(sql, transaction, timeout, commandType, cancellationToken) + ) { var mockDbDataReader = Substitute.For(); @@ -34,8 +21,7 @@ public DbConnectionExtensions_QuerySingleTests() : base( mockDbDataReader.Read().Returns(true, false); mockDbDataReader.ReadAsync(TestContext.Current.CancellationToken).Returns(true, false); - this.MockDbCommand.ExecuteReader(Arg.Any()) - .Returns(mockDbDataReader); + this.MockDbCommand.ExecuteReader(Arg.Any()).Returns(mockDbDataReader); this.MockDbCommand.ExecuteReaderAsync(Arg.Any(), Arg.Any()) .Returns(mockDbDataReader); @@ -44,12 +30,8 @@ public DbConnectionExtensions_QuerySingleTests() : base( [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.QuerySingle("SELECT * FROM Entity") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.QuerySingle("SELECT * FROM Entity")); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.QuerySingleAsync("SELECT * FROM Entity") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.QuerySingleAsync("SELECT * FROM Entity")); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryTests.cs index aa149b6..97b6bd5 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryTests.cs @@ -6,28 +6,16 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; public class DbConnectionExtensions_QueryTests : StatementMethodTestsBase { - public DbConnectionExtensions_QueryTests() : base( - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.QueryAsync(sql, transaction, timeout, commandType, cancellationToken) - .ToListAsync(cancellationToken) - .AsTask(), - ( - connection, - sql, - transaction, - timeout, - commandType, - cancellationToken - ) => - connection.Query(sql, transaction, timeout, commandType, cancellationToken).ToList() - ) + public DbConnectionExtensions_QueryTests() + : base( + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection + .QueryAsync(sql, transaction, timeout, commandType, cancellationToken) + .ToListAsync(cancellationToken) + .AsTask(), + (connection, sql, transaction, timeout, commandType, cancellationToken) => + connection.Query(sql, transaction, timeout, commandType, cancellationToken).ToList() + ) { var mockDbDataReader = Substitute.For(); @@ -35,8 +23,7 @@ public DbConnectionExtensions_QueryTests() : base( mockDbDataReader.GetName(0).Returns("Id"); mockDbDataReader.GetFieldType(0).Returns(typeof(long)); - this.MockDbCommand.ExecuteReader(Arg.Any()) - .Returns(mockDbDataReader); + this.MockDbCommand.ExecuteReader(Arg.Any()).Returns(mockDbDataReader); this.MockDbCommand.ExecuteReaderAsync(Arg.Any(), Arg.Any()) .Returns(mockDbDataReader); @@ -45,12 +32,8 @@ public DbConnectionExtensions_QueryTests() : base( [Fact] public void ShouldGuardAgainstNullArguments() { - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.Query("SELECT * FROM Entity") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.Query("SELECT * FROM Entity")); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.QueryAsync("SELECT * FROM Entity") - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.QueryAsync("SELECT * FROM Entity")); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.TemporaryTableTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.TemporaryTableTests.cs index 4c91821..a2f5d76 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.TemporaryTableTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.TemporaryTableTests.cs @@ -18,20 +18,15 @@ public void TemporaryTable_ShouldInferTableNameFromValuesExpressionIfPossible() static List GetEntityIdsByCategory(string category) => Generate.Ids(); #pragma warning restore RCS1163 // Unused parameter - TemporaryTable(entityIds).Name - .Should().StartWith("EntityIds_"); + TemporaryTable(entityIds).Name.Should().StartWith("EntityIds_"); - TemporaryTable(GetEntityIds()).Name - .Should().StartWith("EntityIds_"); + TemporaryTable(GetEntityIds()).Name.Should().StartWith("EntityIds_"); - TemporaryTable(GetEntityIdsByCategory("Shoes")).Name - .Should().StartWith("EntityIdsByCategoryShoes_"); + TemporaryTable(GetEntityIdsByCategory("Shoes")).Name.Should().StartWith("EntityIdsByCategoryShoes_"); - TemporaryTable(this.testEntityIds).Name - .Should().StartWith("TestEntityIds_"); + TemporaryTable(this.testEntityIds).Name.Should().StartWith("TestEntityIds_"); - TemporaryTable(Get()).Name - .Should().StartWith("Values_"); + TemporaryTable(Get()).Name.Should().StartWith("Values_"); } [Fact] @@ -41,27 +36,21 @@ public void TemporaryTable_ShouldReturnInterpolatedTemporaryTable() var temporaryTable1 = TemporaryTable(entityIds); - temporaryTable1.Values - .Should().BeSameAs(entityIds); + temporaryTable1.Values.Should().BeSameAs(entityIds); - temporaryTable1.ValuesType - .Should().Be(typeof(long)); + temporaryTable1.ValuesType.Should().Be(typeof(long)); - temporaryTable1.Name - .Should().StartWith("EntityIds_"); + temporaryTable1.Name.Should().StartWith("EntityIds_"); var entities = Generate.Multiple(); var temporaryTable2 = TemporaryTable(entities); - temporaryTable2.Values - .Should().BeSameAs(entities); + temporaryTable2.Values.Should().BeSameAs(entities); - temporaryTable2.ValuesType - .Should().Be(typeof(Entity)); + temporaryTable2.ValuesType.Should().Be(typeof(Entity)); - temporaryTable2.Name - .Should().StartWith("Entities_"); + temporaryTable2.Name.Should().StartWith("Entities_"); } [Fact] @@ -70,18 +59,18 @@ public void TemporaryTable_ShouldTruncateInferredTableName() // ReSharper disable once InconsistentNaming int[] longname_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890 = [1, 2, 3]; - TemporaryTable(longname_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890).Name - .Should().HaveLength(60) + TemporaryTable(longname_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890) + .Name.Should() + .HaveLength(60) .And.StartWith("Longname_1234567890_1234567_"); } [Fact] public void TemporaryTable_TIsObject_ShouldThrow() => Invoking(() => TemporaryTable(new List())) - .Should().Throw() - .WithMessage( - $"The type parameter T cannot be the type {typeof(object)}." - ); + .Should() + .Throw() + .WithMessage($"The type parameter T cannot be the type {typeof(object)}."); private readonly List testEntityIds = Generate.Ids(); } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.UpdateEntitiesTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.UpdateEntitiesTests.cs index f6b4691..63b3b7b 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.UpdateEntitiesTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.UpdateEntitiesTests.cs @@ -7,13 +7,9 @@ public void ShouldGuardAgainstNullArguments() { var entities = Generate.Multiple(); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.UpdateEntities(entities) - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.UpdateEntities(entities)); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.UpdateEntitiesAsync(entities) - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.UpdateEntitiesAsync(entities)); } [Fact] @@ -24,22 +20,15 @@ public void UpdateEntities_ShouldCallEntityManipulator() var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.UpdateEntities( - this.MockDbConnection, - entities, - transaction, - cancellationToken - ).Returns(numberOfAffectedRows); + this.MockEntityManipulator.UpdateEntities(this.MockDbConnection, entities, transaction, cancellationToken) + .Returns(numberOfAffectedRows); this.MockDbConnection.UpdateEntities(entities, transaction, cancellationToken) - .Should().Be(numberOfAffectedRows); + .Should() + .Be(numberOfAffectedRows); - this.MockEntityManipulator.Received().UpdateEntities( - this.MockDbConnection, - entities, - transaction, - cancellationToken - ); + this.MockEntityManipulator.Received() + .UpdateEntities(this.MockDbConnection, entities, transaction, cancellationToken); } [Fact] @@ -50,21 +39,15 @@ public async Task UpdateEntitiesAsync_ShouldCallEntityManipulator() var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.UpdateEntitiesAsync( - this.MockDbConnection, - entities, - transaction, - cancellationToken - ).Returns(numberOfAffectedRows); + this.MockEntityManipulator.UpdateEntitiesAsync(this.MockDbConnection, entities, transaction, cancellationToken) + .Returns(numberOfAffectedRows); (await this.MockDbConnection.UpdateEntitiesAsync(entities, transaction, cancellationToken)) - .Should().Be(numberOfAffectedRows); + .Should() + .Be(numberOfAffectedRows); - await this.MockEntityManipulator.Received().UpdateEntitiesAsync( - this.MockDbConnection, - entities, - transaction, - cancellationToken - ); + await this + .MockEntityManipulator.Received() + .UpdateEntitiesAsync(this.MockDbConnection, entities, transaction, cancellationToken); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.UpdateEntityTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.UpdateEntityTests.cs index fdb004b..344fff1 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.UpdateEntityTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.UpdateEntityTests.cs @@ -7,13 +7,9 @@ public void ShouldGuardAgainstNullArguments() { var entity = Generate.Single(); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.UpdateEntity(entity) - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.UpdateEntity(entity)); - ArgumentNullGuardVerifier.Verify(() => - this.MockDbConnection.UpdateEntityAsync(entity) - ); + ArgumentNullGuardVerifier.Verify(() => this.MockDbConnection.UpdateEntityAsync(entity)); } [Fact] @@ -24,22 +20,13 @@ public void UpdateEntity_ShouldCallEntityManipulator() var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.UpdateEntity( - this.MockDbConnection, - entity, - transaction, - cancellationToken - ).Returns(numberOfAffectedRows); + this.MockEntityManipulator.UpdateEntity(this.MockDbConnection, entity, transaction, cancellationToken) + .Returns(numberOfAffectedRows); - this.MockDbConnection.UpdateEntity(entity, transaction, cancellationToken) - .Should().Be(numberOfAffectedRows); + this.MockDbConnection.UpdateEntity(entity, transaction, cancellationToken).Should().Be(numberOfAffectedRows); - this.MockEntityManipulator.Received().UpdateEntity( - this.MockDbConnection, - entity, - transaction, - cancellationToken - ); + this.MockEntityManipulator.Received() + .UpdateEntity(this.MockDbConnection, entity, transaction, cancellationToken); } [Fact] @@ -50,21 +37,15 @@ public async Task UpdateEntityAsync_ShouldCallEntityManipulator() var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.UpdateEntityAsync( - this.MockDbConnection, - entity, - transaction, - cancellationToken - ).Returns(numberOfAffectedRows); + this.MockEntityManipulator.UpdateEntityAsync(this.MockDbConnection, entity, transaction, cancellationToken) + .Returns(numberOfAffectedRows); (await this.MockDbConnection.UpdateEntityAsync(entity, transaction, cancellationToken)) - .Should().Be(numberOfAffectedRows); + .Should() + .Be(numberOfAffectedRows); - await this.MockEntityManipulator.Received().UpdateEntityAsync( - this.MockDbConnection, - entity, - transaction, - cancellationToken - ); + await this + .MockEntityManipulator.Received() + .UpdateEntityAsync(this.MockDbConnection, entity, transaction, cancellationToken); } } diff --git a/tests/DbConnectionPlus.UnitTests/Dynamic/DataRowTests.cs b/tests/DbConnectionPlus.UnitTests/Dynamic/DataRowTests.cs index 8859e52..1795b3f 100644 --- a/tests/DbConnectionPlus.UnitTests/Dynamic/DataRowTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Dynamic/DataRowTests.cs @@ -16,37 +16,31 @@ public void ShouldBeMutable() { { "ColumnA", Generate.ScalarValue() }, { "ColumnB", Generate.ScalarValue() }, - { "ColumnC", Generate.ScalarValue() } + { "ColumnC", Generate.ScalarValue() }, }; var dataRow = new DataRow(dictionary); - dataRow["ColumnA"] - .Should().Be(dictionary["ColumnA"]); + dataRow["ColumnA"].Should().Be(dictionary["ColumnA"]); - dataRow["ColumnB"] - .Should().Be(dictionary["ColumnB"]); + dataRow["ColumnB"].Should().Be(dictionary["ColumnB"]); - dataRow["ColumnC"] - .Should().Be(dictionary["ColumnC"]); + dataRow["ColumnC"].Should().Be(dictionary["ColumnC"]); var newValueA = Generate.ScalarValue(); dataRow["ColumnA"] = newValueA; - dataRow["ColumnA"] - .Should().Be(newValueA); + dataRow["ColumnA"].Should().Be(newValueA); var newValueB = Generate.ScalarValue(); dataRow["ColumnB"] = newValueB; - dataRow["ColumnB"] - .Should().Be(newValueB); + dataRow["ColumnB"].Should().Be(newValueB); var newValueC = Generate.ScalarValue(); dataRow["ColumnC"] = newValueC; - dataRow["ColumnC"] - .Should().Be(newValueC); + dataRow["ColumnC"].Should().Be(newValueC); } [Fact] @@ -55,25 +49,20 @@ public void ShouldAllowDynamicMemberAccess() var dictionary = new Dictionary { { "ColumnA", Generate.ScalarValue() }, - { "ColumnB", Generate.ScalarValue() } + { "ColumnB", Generate.ScalarValue() }, }; dynamic dataRow = new DataRow(dictionary); - ((object?)dataRow.ColumnA) - .Should().Be(dictionary["ColumnA"]); + ((object?)dataRow.ColumnA).Should().Be(dictionary["ColumnA"]); - ((object?)dataRow.ColumnB) - .Should().Be(dictionary["ColumnB"]); + ((object?)dataRow.ColumnB).Should().Be(dictionary["ColumnB"]); } [Fact] public void ShouldAllowDynamicMemberAssignment() { - var dictionary = new Dictionary - { - { "ColumnA", Generate.ScalarValue() } - }; + var dictionary = new Dictionary { { "ColumnA", Generate.ScalarValue() } }; var dataRow = new DataRow(dictionary); dynamic dynamicDataRow = dataRow; @@ -81,11 +70,9 @@ public void ShouldAllowDynamicMemberAssignment() var newValue = Generate.ScalarValue(); dynamicDataRow.ColumnA = newValue; - dataRow["ColumnA"] - .Should().Be(newValue); + dataRow["ColumnA"].Should().Be(newValue); - dictionary["ColumnA"] - .Should().Be(newValue); + dictionary["ColumnA"].Should().Be(newValue); } [Fact] @@ -97,8 +84,7 @@ public void ShouldAllowDynamicMemberAssignmentOfUnknownColumn() var value = Generate.ScalarValue(); dynamicDataRow.NewColumn = value; - dataRow["NewColumn"] - .Should().Be(value); + dataRow["NewColumn"].Should().Be(value); } [Fact] @@ -107,15 +93,14 @@ public void ShouldProvideDynamicMemberNames() var dictionary = new Dictionary { { "ColumnA", Generate.ScalarValue() }, - { "ColumnB", Generate.ScalarValue() } + { "ColumnB", Generate.ScalarValue() }, }; IDynamicMetaObjectProvider dataRow = new DataRow(dictionary); var metaObject = dataRow.GetMetaObject(Expression.Constant(dataRow)); - metaObject.GetDynamicMemberNames() - .Should().BeEquivalentTo("ColumnA", "ColumnB"); + metaObject.GetDynamicMemberNames().Should().BeEquivalentTo("ColumnA", "ColumnB"); } [Fact] @@ -123,8 +108,7 @@ public void ShouldThrowWhenDynamicallyReadingUnknownColumn() { dynamic dataRow = new DataRow(new Dictionary()); - Invoking(() => (object?)dataRow.UnknownColumn) - .Should().Throw(); + Invoking(() => (object?)dataRow.UnknownColumn).Should().Throw(); } [Fact] @@ -133,13 +117,11 @@ public void ShouldResolveDynamicPropertyAccessToColumnsAndNotToOwnProperties() dynamic dataRow = new DataRow(new Dictionary { { "ColumnA", Generate.ScalarValue() } }); // "Count" is a property of DataRow, but through a dynamic reference it addresses a column of that name. - Invoking(() => (object?)dataRow.Count) - .Should().Throw(); + Invoking(() => (object?)dataRow.Count).Should().Throw(); dynamic rowWithShadowingColumn = new DataRow(new Dictionary { { "Count", 42 } }); - ((object?)rowWithShadowingColumn.Count) - .Should().Be(42); + ((object?)rowWithShadowingColumn.Count).Should().Be(42); } [Fact] @@ -147,20 +129,15 @@ public void ShouldResolveDynamicMethodCallsToOwnMembers() { dynamic dataRow = new DataRow(new Dictionary { { "ColumnA", Generate.ScalarValue() } }); - ((bool)dataRow.ContainsKey("ColumnA")) - .Should().BeTrue(); + ((bool)dataRow.ContainsKey("ColumnA")).Should().BeTrue(); - ((bool)dataRow.ContainsKey("ColumnB")) - .Should().BeFalse(); + ((bool)dataRow.ContainsKey("ColumnB")).Should().BeFalse(); } [Fact] public void ShouldForwardAllMethodCallsToDictionary() { - var exceptions = new HashSet - { - nameof(IDictionary<,>.TryGetValue) - }; + var exceptions = new HashSet { nameof(IDictionary<,>.TryGetValue) }; var fixture = new Fixture(); fixture.Customize(new AutoNSubstituteCustomization()); @@ -169,12 +146,7 @@ public void ShouldForwardAllMethodCallsToDictionary() var dictionary = Substitute.For>(); var dataRow = new DataRow(dictionary); - DecoratorAssertions.AssertDecoratorForwardsAllCalls( - fixture, - dataRow, - dictionary, - exceptions - ); + DecoratorAssertions.AssertDecoratorForwardsAllCalls(fixture, dataRow, dictionary, exceptions); } [Fact] @@ -184,19 +156,16 @@ public void ShouldProvideRowData() { { "ColumnA", Generate.ScalarValue() }, { "ColumnB", Generate.ScalarValue() }, - { "ColumnC", Generate.ScalarValue() } + { "ColumnC", Generate.ScalarValue() }, }; var dataRow = new DataRow(dictionary); - dataRow["ColumnA"] - .Should().Be(dictionary["ColumnA"]); + dataRow["ColumnA"].Should().Be(dictionary["ColumnA"]); - dataRow["ColumnB"] - .Should().Be(dictionary["ColumnB"]); + dataRow["ColumnB"].Should().Be(dictionary["ColumnB"]); - dataRow["ColumnC"] - .Should().Be(dictionary["ColumnC"]); + dataRow["ColumnC"].Should().Be(dictionary["ColumnC"]); } [Fact] @@ -207,20 +176,19 @@ public void TryGetValue_ShouldForwardCallToDictionary() var dictionary = Substitute.For>(); - dictionary.TryGetValue(key, out Arg.Any()).Returns(a => + dictionary + .TryGetValue(key, out Arg.Any()) + .Returns(a => { a[1] = value; return true; - } - ); + }); var dataRow = new DataRow(dictionary); - dataRow.TryGetValue(key, out var result) - .Should().BeTrue(); + dataRow.TryGetValue(key, out var result).Should().BeTrue(); - result - .Should().Be(value); + result.Should().Be(value); dictionary.Received().TryGetValue(key, out Arg.Any()); } diff --git a/tests/DbConnectionPlus.UnitTests/Entities/EntityHelperTests.cs b/tests/DbConnectionPlus.UnitTests/Entities/EntityHelperTests.cs index eaed607..a95b4d9 100644 --- a/tests/DbConnectionPlus.UnitTests/Entities/EntityHelperTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Entities/EntityHelperTests.cs @@ -16,13 +16,13 @@ public void FindCompatibleConstructor_MatchingPrivateConstructor_ShouldReturnPri [("c", typeof(long)), ("b", typeof(int)), ("a", typeof(short))] ); - constructor - .Should().NotBeNull(); + constructor.Should().NotBeNull(); constructor .GetParameters() .Select(a => (a.Name, a.ParameterType)) - .Should().BeEquivalentTo([("a", typeof(short)), ("b", typeof(int)), ("c", typeof(long))]); + .Should() + .BeEquivalentTo([("a", typeof(short)), ("b", typeof(int)), ("c", typeof(long))]); } [Fact] @@ -33,22 +33,24 @@ public void FindCompatibleConstructor_NamesAndTypesMatchWithDifferentOrder_Shoul [("c", typeof(long)), ("b", typeof(int)), ("a", typeof(short))] ); - constructor - .Should().NotBeNull(); + constructor.Should().NotBeNull(); constructor .GetParameters() .Select(a => (a.Name, a.ParameterType)) - .Should().BeEquivalentTo([("a", typeof(short)), ("b", typeof(int)), ("c", typeof(long))]); + .Should() + .BeEquivalentTo([("a", typeof(short)), ("b", typeof(int)), ("c", typeof(long))]); } [Fact] public void FindCompatibleConstructor_NamesDoNotMatch_TypesMatch_ShouldReturnNull() => - EntityHelper.FindCompatibleConstructor( + EntityHelper + .FindCompatibleConstructor( typeof(ItemWithConstructor), [("d", typeof(short)), ("e", typeof(int)), ("f", typeof(long))] ) - .Should().BeNull(); + .Should() + .BeNull(); [Fact] public void FindCompatibleConstructor_NamesMatch_TypesAreCompatible_ShouldReturnConstructor() @@ -58,22 +60,24 @@ public void FindCompatibleConstructor_NamesMatch_TypesAreCompatible_ShouldReturn [("a", typeof(int)), ("b", typeof(int)), ("c", typeof(int))] ); - constructor - .Should().NotBeNull(); + constructor.Should().NotBeNull(); constructor .GetParameters() .Select(a => (a.Name, a.ParameterType)) - .Should().BeEquivalentTo([("a", typeof(short)), ("b", typeof(int)), ("c", typeof(long))]); + .Should() + .BeEquivalentTo([("a", typeof(short)), ("b", typeof(int)), ("c", typeof(long))]); } [Fact] public void FindCompatibleConstructor_NamesMatch_TypesAreIncompatible_ShouldReturnNull() => - EntityHelper.FindCompatibleConstructor( + EntityHelper + .FindCompatibleConstructor( typeof(ItemWithConstructor), [("a", typeof(short)), ("b", typeof(int)), ("c", typeof(TimeSpan))] ) - .Should().BeNull(); + .Should() + .BeNull(); [Fact] public void FindCompatibleConstructor_NamesMatch_TypesMatch_ShouldReturnConstructor() @@ -83,13 +87,13 @@ public void FindCompatibleConstructor_NamesMatch_TypesMatch_ShouldReturnConstruc [("a", typeof(short)), ("b", typeof(int)), ("c", typeof(long))] ); - constructor - .Should().NotBeNull(); + constructor.Should().NotBeNull(); constructor .GetParameters() .Select(a => (a.Name, a.ParameterType)) - .Should().BeEquivalentTo([("a", typeof(short)), ("b", typeof(int)), ("c", typeof(long))]); + .Should() + .BeEquivalentTo([("a", typeof(short)), ("b", typeof(int)), ("c", typeof(long))]); } [Fact] @@ -100,30 +104,31 @@ public void FindCompatibleConstructor_NamesMatchWithDifferentCasing_TypesMatch_S [("A", typeof(short)), ("B", typeof(int)), ("C", typeof(long))] ); - constructor - .Should().NotBeNull(); + constructor.Should().NotBeNull(); constructor .GetParameters() .Select(a => a.ParameterType) - .Should().BeEquivalentTo([typeof(short), typeof(int), typeof(long)]); + .Should() + .BeEquivalentTo([typeof(short), typeof(int), typeof(long)]); } [Fact] public void FindCompatibleConstructor_NoMatchingConstructor_ShouldReturnNull() => - EntityHelper.FindCompatibleConstructor( + EntityHelper + .FindCompatibleConstructor( typeof(ItemWithConstructor), [("a", typeof(short)), ("b", typeof(int)), ("c", typeof(long)), ("d", typeof(string))] ) - .Should().BeNull(); + .Should() + .BeNull(); [Fact] public void FindParameterlessConstructor_NoParameterlessConstructor_ShouldReturnNull() { var constructor = EntityHelper.FindParameterlessConstructor(typeof(EntityWithPublicConstructor)); - constructor - .Should().BeNull(); + constructor.Should().BeNull(); } [Fact] @@ -132,7 +137,8 @@ public void FindParameterlessConstructor_PrivateParameterlessConstructor_ShouldR var constructor = EntityHelper.FindParameterlessConstructor(typeof(ItemWithPrivateParameterlessConstructor)); constructor - .Should().BeSameAs( + .Should() + .BeSameAs( typeof(ItemWithPrivateParameterlessConstructor).GetConstructor( BindingFlags.NonPublic | BindingFlags.Instance, Type.EmptyTypes @@ -146,9 +152,8 @@ public void FindParameterlessConstructor_PublicParameterlessConstructor_ShouldRe var constructor = EntityHelper.FindParameterlessConstructor(typeof(Entity)); constructor - .Should().BeSameAs( - typeof(Entity).GetConstructor(BindingFlags.Public | BindingFlags.Instance, Type.EmptyTypes) - ); + .Should() + .BeSameAs(typeof(Entity).GetConstructor(BindingFlags.Public | BindingFlags.Instance, Type.EmptyTypes)); } [Fact] @@ -162,79 +167,75 @@ public void GetEntityTypeMetadata_Mapping_Attributes_ShouldGetMetadataBasedOnAtt var entityType = typeof(MappingTestEntityAttributes); - var entity = specimenFactoryCreateMethod - .MakeGenericMethod(entityType) - .Invoke(null, [fixture])!; + var entity = specimenFactoryCreateMethod.MakeGenericMethod(entityType).Invoke(null, [fixture])!; var entityProperties = entityType.GetProperties(BindingFlags.Public | BindingFlags.Instance); var metadata = EntityHelper.GetEntityTypeMetadata(entityType); - metadata - .Should().NotBeNull(); + metadata.Should().NotBeNull(); - metadata.EntityType - .Should().Be(entityType); + metadata.EntityType.Should().Be(entityType); - metadata.TableName - .Should().Be(entityType.GetCustomAttribute()?.Name ?? entityType.Name); + metadata.TableName.Should().Be(entityType.GetCustomAttribute()?.Name ?? entityType.Name); var allPropertiesMetadata = metadata.AllProperties; - allPropertiesMetadata - .Should().HaveSameCount(entityProperties); + allPropertiesMetadata.Should().HaveSameCount(entityProperties); - metadata.AllPropertiesByPropertyName - .Should().BeEquivalentTo(allPropertiesMetadata.ToDictionary(a => a.PropertyName)); + metadata + .AllPropertiesByPropertyName.Should() + .BeEquivalentTo(allPropertiesMetadata.ToDictionary(a => a.PropertyName)); - metadata.ComputedProperties - .Should() + metadata + .ComputedProperties.Should() .BeEquivalentTo(allPropertiesMetadata.Where(a => a is { IsIgnored: false, IsComputed: true })); - metadata.ConcurrencyTokenProperties - .Should() + metadata + .ConcurrencyTokenProperties.Should() .BeEquivalentTo(allPropertiesMetadata.Where(a => a is { IsIgnored: false, IsConcurrencyToken: true })); - metadata.DatabaseGeneratedProperties - .Should() + metadata + .DatabaseGeneratedProperties.Should() .BeEquivalentTo( allPropertiesMetadata.Where(a => !a.IsIgnored && (a.IsComputed || a.IsIdentity || a.IsRowVersion)) ); - metadata.IdentityProperty - .Should() + metadata + .IdentityProperty.Should() .Be(allPropertiesMetadata.FirstOrDefault(a => a is { IsIgnored: false, IsIdentity: true })); - metadata.InsertProperties - .Should().BeEquivalentTo( - allPropertiesMetadata.Where(a => a is - { IsIgnored: false, IsComputed: false, IsIdentity: false, IsRowVersion: false } + metadata + .InsertProperties.Should() + .BeEquivalentTo( + allPropertiesMetadata.Where(a => + a is { IsIgnored: false, IsComputed: false, IsIdentity: false, IsRowVersion: false } ) ); - metadata.KeyProperties - .Should() + metadata + .KeyProperties.Should() .BeEquivalentTo(allPropertiesMetadata.Where(a => a is { IsIgnored: false, IsKey: true })); - metadata.MappedProperties - .Should() - .BeEquivalentTo(allPropertiesMetadata.Where(a => a is { IsIgnored: false })); + metadata.MappedProperties.Should().BeEquivalentTo(allPropertiesMetadata.Where(a => a is { IsIgnored: false })); - metadata.RowVersionProperties - .Should() + metadata + .RowVersionProperties.Should() .BeEquivalentTo(allPropertiesMetadata.Where(a => a is { IsRowVersion: true })); - metadata.UpdateProperties - .Should().BeEquivalentTo( - allPropertiesMetadata.Where(a => a is - { - IsComputed: false, - IsConcurrencyToken: false, - IsIgnored: false, - IsIdentity: false, - IsKey: false, - IsRowVersion: false - } + metadata + .UpdateProperties.Should() + .BeEquivalentTo( + allPropertiesMetadata.Where(a => + a + is { + IsComputed: false, + IsConcurrencyToken: false, + IsIgnored: false, + IsIdentity: false, + IsKey: false, + IsRowVersion: false + } ) ); @@ -242,66 +243,58 @@ public void GetEntityTypeMetadata_Mapping_Attributes_ShouldGetMetadataBasedOnAtt { var propertyMetadata = allPropertiesMetadata.FirstOrDefault(a => a.PropertyName == property.Name); - propertyMetadata - .Should().NotBeNull(); + propertyMetadata.Should().NotBeNull(); - propertyMetadata.CanRead - .Should().Be(property.CanRead); + propertyMetadata.CanRead.Should().Be(property.CanRead); - propertyMetadata.CanWrite - .Should().Be(property.CanWrite); + propertyMetadata.CanWrite.Should().Be(property.CanWrite); - propertyMetadata.ColumnName - .Should().Be(property.GetCustomAttribute()?.Name ?? property.Name); + propertyMetadata + .ColumnName.Should() + .Be(property.GetCustomAttribute()?.Name ?? property.Name); - propertyMetadata.IsComputed - .Should().Be( - property.GetCustomAttribute()?.DatabaseGeneratedOption is - DatabaseGeneratedOption.Computed + propertyMetadata + .IsComputed.Should() + .Be( + property.GetCustomAttribute()?.DatabaseGeneratedOption + is DatabaseGeneratedOption.Computed ); - propertyMetadata.IsConcurrencyToken - .Should().Be(property.GetCustomAttribute() is not null); + propertyMetadata + .IsConcurrencyToken.Should() + .Be(property.GetCustomAttribute() is not null); - propertyMetadata.IsIdentity - .Should().Be( - property.GetCustomAttribute()?.DatabaseGeneratedOption is - DatabaseGeneratedOption.Identity + propertyMetadata + .IsIdentity.Should() + .Be( + property.GetCustomAttribute()?.DatabaseGeneratedOption + is DatabaseGeneratedOption.Identity ); - propertyMetadata.IsIgnored - .Should().Be(property.GetCustomAttribute() is not null); + propertyMetadata.IsIgnored.Should().Be(property.GetCustomAttribute() is not null); - propertyMetadata.IsKey - .Should().Be(property.GetCustomAttribute() is not null); + propertyMetadata.IsKey.Should().Be(property.GetCustomAttribute() is not null); - propertyMetadata.IsRowVersion - .Should().Be(property.GetCustomAttribute() is not null); + propertyMetadata.IsRowVersion.Should().Be(property.GetCustomAttribute() is not null); if (propertyMetadata.CanRead) { - propertyMetadata.PropertyGetter - .Should().NotBeNull(); + propertyMetadata.PropertyGetter.Should().NotBeNull(); - propertyMetadata.PropertyGetter(entity) - .Should().Be(property.GetValue(entity)); + propertyMetadata.PropertyGetter(entity).Should().Be(property.GetValue(entity)); } else { - propertyMetadata.PropertyGetter - .Should().BeNull(); + propertyMetadata.PropertyGetter.Should().BeNull(); } - propertyMetadata.PropertyInfo - .Should().BeSameAs(property); + propertyMetadata.PropertyInfo.Should().BeSameAs(property); - propertyMetadata.PropertyName - .Should().Be(property.Name); + propertyMetadata.PropertyName.Should().Be(property.Name); if (propertyMetadata.CanWrite) { - propertyMetadata.PropertySetter - .Should().NotBeNull(); + propertyMetadata.PropertySetter.Should().NotBeNull(); var value = specimenFactoryCreateMethod .MakeGenericMethod(property.PropertyType) @@ -309,17 +302,14 @@ public void GetEntityTypeMetadata_Mapping_Attributes_ShouldGetMetadataBasedOnAtt propertyMetadata.PropertySetter(entity, value); - property.GetValue(entity) - .Should().Be(value); + property.GetValue(entity).Should().Be(value); } else { - propertyMetadata.PropertySetter - .Should().BeNull(); + propertyMetadata.PropertySetter.Should().BeNull(); } - propertyMetadata.PropertyType - .Should().Be(property.PropertyType); + propertyMetadata.PropertyType.Should().Be(property.PropertyType); } } @@ -330,126 +320,113 @@ public void GetEntityTypeMetadata_Mapping_FluentApi_ShouldGetMetadataBasedOnFlue var metadata = EntityHelper.GetEntityTypeMetadata(typeof(MappingTestEntityFluentApi)); - metadata - .Should().NotBeNull(); + metadata.Should().NotBeNull(); - metadata.EntityType - .Should().Be(typeof(MappingTestEntityFluentApi)); + metadata.EntityType.Should().Be(typeof(MappingTestEntityFluentApi)); - metadata.TableName - .Should().Be("MappingTestEntity"); + metadata.TableName.Should().Be("MappingTestEntity"); - metadata.AllProperties - .Should().HaveCount(8); + metadata.AllProperties.Should().HaveCount(8); - metadata.AllPropertiesByPropertyName - .Should().BeEquivalentTo(metadata.AllProperties.ToDictionary(a => a.PropertyName)); + metadata + .AllPropertiesByPropertyName.Should() + .BeEquivalentTo(metadata.AllProperties.ToDictionary(a => a.PropertyName)); var computedProperty = metadata.AllPropertiesByPropertyName["Computed_"]; - computedProperty.ColumnName - .Should().Be("Computed"); + computedProperty.ColumnName.Should().Be("Computed"); - computedProperty.IsComputed - .Should().BeTrue(); + computedProperty.IsComputed.Should().BeTrue(); var concurrencyTokenProperty = metadata.AllPropertiesByPropertyName["ConcurrencyToken_"]; - concurrencyTokenProperty.ColumnName - .Should().Be("ConcurrencyToken"); + concurrencyTokenProperty.ColumnName.Should().Be("ConcurrencyToken"); - concurrencyTokenProperty.IsConcurrencyToken - .Should().BeTrue(); + concurrencyTokenProperty.IsConcurrencyToken.Should().BeTrue(); var identityProperty = metadata.AllPropertiesByPropertyName["Identity_"]; - identityProperty.ColumnName - .Should().Be("Identity"); + identityProperty.ColumnName.Should().Be("Identity"); - identityProperty.IsIdentity - .Should().BeTrue(); + identityProperty.IsIdentity.Should().BeTrue(); var key1Property = metadata.AllPropertiesByPropertyName["Key1_"]; - key1Property.ColumnName - .Should().Be("Key1"); + key1Property.ColumnName.Should().Be("Key1"); - key1Property.IsKey - .Should().BeTrue(); + key1Property.IsKey.Should().BeTrue(); var key2Property = metadata.AllPropertiesByPropertyName["Key2_"]; - key2Property.ColumnName - .Should().Be("Key2"); + key2Property.ColumnName.Should().Be("Key2"); - key2Property.IsKey - .Should().BeTrue(); + key2Property.IsKey.Should().BeTrue(); var nameProperty = metadata.AllPropertiesByPropertyName["Value_"]; - nameProperty.ColumnName - .Should().Be("Value"); + nameProperty.ColumnName.Should().Be("Value"); var notMappedProperty = metadata.AllPropertiesByPropertyName["NotMapped"]; - notMappedProperty.IsIgnored - .Should().BeTrue(); + notMappedProperty.IsIgnored.Should().BeTrue(); var rowVersionProperty = metadata.AllPropertiesByPropertyName["RowVersion_"]; - rowVersionProperty.IsRowVersion - .Should().BeTrue(); - - metadata.ComputedProperties - .Should().BeEquivalentTo([computedProperty]); + rowVersionProperty.IsRowVersion.Should().BeTrue(); - metadata.ConcurrencyTokenProperties - .Should().BeEquivalentTo([concurrencyTokenProperty]); + metadata.ComputedProperties.Should().BeEquivalentTo([computedProperty]); - metadata.DatabaseGeneratedProperties - .Should().BeEquivalentTo([computedProperty, identityProperty, rowVersionProperty]); + metadata.ConcurrencyTokenProperties.Should().BeEquivalentTo([concurrencyTokenProperty]); - metadata.IdentityProperty - .Should().Be(identityProperty); - - metadata.InsertProperties - .Should().BeEquivalentTo([concurrencyTokenProperty, key1Property, key2Property, nameProperty]); + metadata + .DatabaseGeneratedProperties.Should() + .BeEquivalentTo([computedProperty, identityProperty, rowVersionProperty]); - metadata.KeyProperties - .Should().BeEquivalentTo([key1Property, key2Property]); + metadata.IdentityProperty.Should().Be(identityProperty); - metadata.MappedProperties - .Should().BeEquivalentTo( - [ - computedProperty, concurrencyTokenProperty, identityProperty, key1Property, key2Property, - nameProperty, rowVersionProperty - ] - ); + metadata + .InsertProperties.Should() + .BeEquivalentTo([concurrencyTokenProperty, key1Property, key2Property, nameProperty]); - metadata.RowVersionProperties - .Should().BeEquivalentTo( - [rowVersionProperty] - ); + metadata.KeyProperties.Should().BeEquivalentTo([key1Property, key2Property]); - metadata.UpdateProperties - .Should().BeEquivalentTo([nameProperty]); + metadata + .MappedProperties.Should() + .BeEquivalentTo([ + computedProperty, + concurrencyTokenProperty, + identityProperty, + key1Property, + key2Property, + nameProperty, + rowVersionProperty, + ]); + + metadata.RowVersionProperties.Should().BeEquivalentTo([rowVersionProperty]); + + metadata.UpdateProperties.Should().BeEquivalentTo([nameProperty]); } [Fact] public void GetEntityTypeMetadata_MoreThanOneIdentityProperty_ShouldThrow() => Invoking(() => EntityHelper.GetEntityTypeMetadata(typeof(EntityWithMultipleIdentityProperties))) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "There are multiple identity properties defined for the entity type " + - $"{typeof(EntityWithMultipleIdentityProperties)}. Only one property can be marked as an identity " + - "property per entity type." + "There are multiple identity properties defined for the entity type " + + $"{typeof(EntityWithMultipleIdentityProperties)}. Only one property can be marked as an identity " + + "property per entity type." ); [Fact] public void ShouldGuardAgainstNullArguments() { (string Name, Type Type)[] constructorParameters = - [("a", typeof(short)), ("b", typeof(int)), ("c", typeof(long))]; + [ + ("a", typeof(short)), + ("b", typeof(int)), + ("c", typeof(long)), + ]; ArgumentNullGuardVerifier.Verify(() => EntityHelper.FindCompatibleConstructor(typeof(ItemWithConstructor), constructorParameters) @@ -465,15 +442,16 @@ public void GetEntityTypeMetadata_ShouldNotInvokePropertyAccessorsWhileCreatingM // resolved and invoked eagerly. var metadata = EntityHelper.GetEntityTypeMetadata(typeof(EntityWithThrowingAccessors)); - var property = metadata.MappedProperties - .Single(p => p.PropertyName == nameof(EntityWithThrowingAccessors.Value)); + var property = metadata.MappedProperties.Single(p => + p.PropertyName == nameof(EntityWithThrowingAccessors.Value) + ); - property.PropertyGetter - .Should().NotBeNull(); + property.PropertyGetter.Should().NotBeNull(); // The accessor is real - it simply had not been called yet. Invoking(() => property.PropertyGetter!(new EntityWithThrowingAccessors())) - .Should().Throw() + .Should() + .Throw() .WithMessage("Getter was invoked."); } @@ -482,8 +460,7 @@ public void GetEntityTypeMetadata_PropertyAccessors_ShouldWorkAcrossRepeatedCall { var metadata = EntityHelper.GetEntityTypeMetadata(typeof(EntityWithNonPublicSetter)); - var property = metadata.MappedProperties - .Single(p => p.PropertyName == nameof(EntityWithNonPublicSetter.Value)); + var property = metadata.MappedProperties.Single(p => p.PropertyName == nameof(EntityWithNonPublicSetter.Value)); var entity = new EntityWithNonPublicSetter(); @@ -491,8 +468,7 @@ public void GetEntityTypeMetadata_PropertyAccessors_ShouldWorkAcrossRepeatedCall { property.PropertySetter!(entity, value); - property.PropertyGetter!(entity) - .Should().Be(value); + property.PropertyGetter!(entity).Should().Be(value); } } @@ -501,33 +477,32 @@ public void GetEntityTypeMetadata_ShouldCreateAccessorsForNonPublicAndInitOnlySe { var metadata = EntityHelper.GetEntityTypeMetadata(typeof(EntityWithNonPublicSetter)); - var privateSetterProperty = metadata.MappedProperties - .Single(p => p.PropertyName == nameof(EntityWithNonPublicSetter.Value)); + var privateSetterProperty = metadata.MappedProperties.Single(p => + p.PropertyName == nameof(EntityWithNonPublicSetter.Value) + ); - var initOnlyProperty = metadata.MappedProperties - .Single(p => p.PropertyName == nameof(EntityWithNonPublicSetter.Name)); + var initOnlyProperty = metadata.MappedProperties.Single(p => + p.PropertyName == nameof(EntityWithNonPublicSetter.Name) + ); var entity = new EntityWithNonPublicSetter(); privateSetterProperty.PropertySetter!(entity, 42); initOnlyProperty.PropertySetter!(entity, "Ada"); - entity.Value - .Should().Be(42); + entity.Value.Should().Be(42); - entity.Name - .Should().Be("Ada"); + entity.Name.Should().Be("Ada"); } /// /// The method. /// - private static readonly MethodInfo specimenFactoryCreateMethod = typeof(SpecimenFactory) - .GetMethod( - nameof(SpecimenFactory.Create), - BindingFlags.Public | BindingFlags.Static, - [typeof(ISpecimenBuilder)] - )!; + private static readonly MethodInfo specimenFactoryCreateMethod = typeof(SpecimenFactory).GetMethod( + nameof(SpecimenFactory.Create), + BindingFlags.Public | BindingFlags.Static, + [typeof(ISpecimenBuilder)] + )!; /// /// An entity whose property accessors throw, used to prove that creating metadata does not invoke them. diff --git a/tests/DbConnectionPlus.UnitTests/Extensions/DbDataReaderExtensionsTests.cs b/tests/DbConnectionPlus.UnitTests/Extensions/DbDataReaderExtensionsTests.cs index c156d13..e5b1b1b 100644 --- a/tests/DbConnectionPlus.UnitTests/Extensions/DbDataReaderExtensionsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Extensions/DbDataReaderExtensionsTests.cs @@ -19,8 +19,7 @@ public void GetFieldNames_ShouldReturnFieldNames() dataReader.GetName(1).Returns(fieldNames[1]); dataReader.GetName(2).Returns(fieldNames[2]); - dataReader.GetFieldNames() - .Should().BeEquivalentTo(fieldNames); + dataReader.GetFieldNames().Should().BeEquivalentTo(fieldNames); } [Fact] @@ -36,8 +35,7 @@ public void GetFieldTypes_ShouldReturnFieldTypes() dataReader.GetFieldType(1).Returns(fieldTypes[1]); dataReader.GetFieldType(2).Returns(fieldTypes[2]); - dataReader.GetFieldTypes() - .Should().BeEquivalentTo(fieldTypes); + dataReader.GetFieldTypes().Should().BeEquivalentTo(fieldTypes); } [Fact] diff --git a/tests/DbConnectionPlus.UnitTests/Extensions/Int32ExtensionsTests.cs b/tests/DbConnectionPlus.UnitTests/Extensions/Int32ExtensionsTests.cs index 280a0b9..ec1b5a2 100644 --- a/tests/DbConnectionPlus.UnitTests/Extensions/Int32ExtensionsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Extensions/Int32ExtensionsTests.cs @@ -17,6 +17,5 @@ public class Int32ExtensionsTests : UnitTestsBase [InlineData(24, "24th")] [InlineData(25, "25th")] public void OrdinalizeEnglish_ShouldOrdinalizeNumberInEnglishFormat(int number, string expectedResult) => - number.OrdinalizeEnglish() - .Should().Be(expectedResult); + number.OrdinalizeEnglish().Should().Be(expectedResult); } diff --git a/tests/DbConnectionPlus.UnitTests/Extensions/ObjectExtensionsTests.cs b/tests/DbConnectionPlus.UnitTests/Extensions/ObjectExtensionsTests.cs index 3763a1e..dfc397d 100644 --- a/tests/DbConnectionPlus.UnitTests/Extensions/ObjectExtensionsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Extensions/ObjectExtensionsTests.cs @@ -10,25 +10,31 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.Extensions; public class ObjectExtensionsTests : UnitTestsBase { [Fact] - public void ToDebugString_ShouldUseToStringForUnhandledTypes() => new Item("A").ToDebugString() - .Should().Be( - "'Item A' (RentADeveloper.DbConnectionPlus.UnitTests.Extensions.ObjectExtensionsTests+Item)" - ); + public void ToDebugString_ShouldUseToStringForUnhandledTypes() => + new Item("A") + .ToDebugString() + .Should() + .Be("'Item A' (RentADeveloper.DbConnectionPlus.UnitTests.Extensions.ObjectExtensionsTests+Item)"); [Fact] public void ToDebugString_ShouldRenderSequencesElementByElement() { - new List { "A", "B" }.ToDebugString() - .Should().Be("'[A,B]' (System.Collections.Generic.List`1[System.String])"); - - new object?[] { 1, null, "A", true }.ToDebugString() - .Should().Be("'[1,{null},A,True]' (System.Object[])"); - - new int[][] { [1, 2], [3] }.ToDebugString() - .Should().Be("'[[1,2],[3]]' (System.Int32[][])"); - - Array.Empty().ToDebugString() - .Should().Be("'[]' (System.Int32[])"); + new List { "A", "B" } + .ToDebugString() + .Should() + .Be("'[A,B]' (System.Collections.Generic.List`1[System.String])"); + + new object?[] { 1, null, "A", true } + .ToDebugString() + .Should() + .Be("'[1,{null},A,True]' (System.Object[])"); + + new int[][] { [1, 2], [3] } + .ToDebugString() + .Should() + .Be("'[[1,2],[3]]' (System.Int32[][])"); + + Array.Empty().ToDebugString().Should().Be("'[]' (System.Int32[])"); } [Fact] @@ -51,98 +57,91 @@ public void ToDebugString_ShouldTruncateSelfReferencingSequencesInsteadOfRecursi public void ToDebugString_ShouldReturnStringRepresentationOfValue() { #pragma warning disable RCS1202 - (null as object).ToDebugString() - .Should().Be("{null}"); + (null as object).ToDebugString().Should().Be("{null}"); #pragma warning restore RCS1202 - DBNull.Value.ToDebugString() - .Should().Be("{DBNull}"); + DBNull.Value.ToDebugString().Should().Be("{DBNull}"); - true.ToDebugString() - .Should().Be("'True' (System.Boolean)"); + true.ToDebugString().Should().Be("'True' (System.Boolean)"); - ((byte)123).ToDebugString() - .Should().Be("'123' (System.Byte)"); + ((byte)123).ToDebugString().Should().Be("'123' (System.Byte)"); - new byte[] { 1, 2, 3 }.ToDebugString() - .Should().Be("'AQID' (System.Byte[])"); + new byte[] { 1, 2, 3 } + .ToDebugString() + .Should() + .Be("'AQID' (System.Byte[])"); - 'X'.ToDebugString() - .Should().Be("'X' (System.Char)"); + 'X'.ToDebugString().Should().Be("'X' (System.Char)"); - new DateTime(2025, 12, 31, 23, 59, 59, 999).ToDebugString() - .Should().Be("'2025-12-31T23:59:59.9990000' (System.DateTime)"); + new DateTime(2025, 12, 31, 23, 59, 59, 999) + .ToDebugString() + .Should() + .Be("'2025-12-31T23:59:59.9990000' (System.DateTime)"); - new DateTimeOffset(2025, 12, 31, 23, 59, 59, TimeSpan.FromHours(1)).ToDebugString() - .Should().Be("'2025-12-31T23:59:59.0000000+01:00' (System.DateTimeOffset)"); + new DateTimeOffset(2025, 12, 31, 23, 59, 59, TimeSpan.FromHours(1)) + .ToDebugString() + .Should() + .Be("'2025-12-31T23:59:59.0000000+01:00' (System.DateTimeOffset)"); - 123.45M.ToDebugString() - .Should().Be("'123.45' (System.Decimal)"); + 123.45M.ToDebugString().Should().Be("'123.45' (System.Decimal)"); - 123.45.ToDebugString() - .Should().Be("'123.45' (System.Double)"); + 123.45.ToDebugString().Should().Be("'123.45' (System.Double)"); - TestEnum.Value3.ToDebugString() - .Should().Be("'Value3' (RentADeveloper.DbConnectionPlus.UnitTests.TestData.TestEnum)"); + TestEnum + .Value3.ToDebugString() + .Should() + .Be("'Value3' (RentADeveloper.DbConnectionPlus.UnitTests.TestData.TestEnum)"); - new Guid("889a8be0-f0ff-4555-86d8-8490434b7def").ToDebugString() - .Should().Be("'889a8be0-f0ff-4555-86d8-8490434b7def' (System.Guid)"); + new Guid("889a8be0-f0ff-4555-86d8-8490434b7def") + .ToDebugString() + .Should() + .Be("'889a8be0-f0ff-4555-86d8-8490434b7def' (System.Guid)"); - ((short)123).ToDebugString() - .Should().Be("'123' (System.Int16)"); + ((short)123).ToDebugString().Should().Be("'123' (System.Int16)"); - 123.ToDebugString() - .Should().Be("'123' (System.Int32)"); + 123.ToDebugString().Should().Be("'123' (System.Int32)"); - ((long)123).ToDebugString() - .Should().Be("'123' (System.Int64)"); + ((long)123).ToDebugString().Should().Be("'123' (System.Int64)"); - ((IntPtr)123).ToDebugString() - .Should().Be("'123' (System.IntPtr)"); + ((IntPtr)123).ToDebugString().Should().Be("'123' (System.IntPtr)"); - ((sbyte)123).ToDebugString() - .Should().Be("'123' (System.SByte)"); + ((sbyte)123).ToDebugString().Should().Be("'123' (System.SByte)"); - ((float)123.45).ToDebugString() - .Should().Be("'123.449997' (System.Single)"); + ((float)123.45).ToDebugString().Should().Be("'123.449997' (System.Single)"); - "A String".ToDebugString() - .Should().Be("'A String' (System.String)"); + "A String".ToDebugString().Should().Be("'A String' (System.String)"); - new TimeSpan(1, 2, 3, 4).ToDebugString() - .Should().Be("'1.02:03:04' (System.TimeSpan)"); + new TimeSpan(1, 2, 3, 4).ToDebugString().Should().Be("'1.02:03:04' (System.TimeSpan)"); - ((ushort)123).ToDebugString() - .Should().Be("'123' (System.UInt16)"); + ((ushort)123).ToDebugString().Should().Be("'123' (System.UInt16)"); - ((uint)123).ToDebugString() - .Should().Be("'123' (System.UInt32)"); + ((uint)123).ToDebugString().Should().Be("'123' (System.UInt32)"); - ((ulong)123).ToDebugString() - .Should().Be("'123' (System.UInt64)"); + ((ulong)123).ToDebugString().Should().Be("'123' (System.UInt64)"); - ((UIntPtr)123).ToDebugString() - .Should().Be("'123' (System.UIntPtr)"); + ((UIntPtr)123).ToDebugString().Should().Be("'123' (System.UIntPtr)"); #pragma warning disable CA1861 // Avoid constant arrays as arguments - new int[] { 1, 2, 3 }.ToDebugString() - .Should().Be("'[1,2,3]' (System.Int32[])"); + new int[] { 1, 2, 3 } + .ToDebugString() + .Should() + .Be("'[1,2,3]' (System.Int32[])"); #pragma warning restore CA1861 // Avoid constant arrays as arguments - new object().ToDebugString() - .Should().Be("'System.Object' (System.Object)"); + new object().ToDebugString().Should().Be("'System.Object' (System.Object)"); - new EntityWithEnumStoredAsString { Enum = TestEnum.Value3, Id = 1 }.ToDebugString() - .Should().Be( - "'EntityWithEnumStoredAsString { Enum = Value3, Id = 1 }' " + - "(RentADeveloper.DbConnectionPlus.UnitTests.TestData.EntityWithEnumStoredAsString)" + new EntityWithEnumStoredAsString { Enum = TestEnum.Value3, Id = 1 } + .ToDebugString() + .Should() + .Be( + "'EntityWithEnumStoredAsString { Enum = Value3, Id = 1 }' " + + "(RentADeveloper.DbConnectionPlus.UnitTests.TestData.EntityWithEnumStoredAsString)" ); } private sealed class Item(string id) { /// - public override string ToString() => - $"Item {id}"; + public override string ToString() => $"Item {id}"; } } diff --git a/tests/DbConnectionPlus.UnitTests/Extensions/TypeExtensionsTests.cs b/tests/DbConnectionPlus.UnitTests/Extensions/TypeExtensionsTests.cs index 66c5971..6bc158d 100644 --- a/tests/DbConnectionPlus.UnitTests/Extensions/TypeExtensionsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Extensions/TypeExtensionsTests.cs @@ -56,9 +56,7 @@ public class TypeExtensionsTests : UnitTestsBase public void IsBuiltInTypeOrNullableBuiltInType_ShouldDetermineWhetherTypeIsBuiltInTypeOrNullableBuiltInType( Type type, bool expectedResult - ) => - type.IsBuiltInTypeOrNullableBuiltInType() - .Should().Be(expectedResult); + ) => type.IsBuiltInTypeOrNullableBuiltInType().Should().Be(expectedResult); [Theory] [InlineData(typeof(char), true)] @@ -69,9 +67,7 @@ bool expectedResult public void IsCharOrNullableCharType_ShouldDetermineWhetherTypeIsCharOrNullableCharType( Type type, bool expectedResult - ) => - type.IsCharOrNullableCharType() - .Should().Be(expectedResult); + ) => type.IsCharOrNullableCharType().Should().Be(expectedResult); [Theory] [InlineData(typeof(TestEnum), true)] @@ -84,9 +80,7 @@ bool expectedResult public void IsEnumOrNullableEnumType_ShouldDetermineWhetherTypeIsEnumTypeOrNullableEnumType( Type type, bool expectedResult - ) => - type.IsEnumOrNullableEnumType() - .Should().Be(expectedResult); + ) => type.IsEnumOrNullableEnumType().Should().Be(expectedResult); [Theory] [InlineData(typeof(int?), true)] @@ -100,9 +94,7 @@ bool expectedResult public void IsReferenceTypeOrNullableType_ShouldDetermineWhetherTypeIsReferenceTypeOrNullableType( Type type, bool expectedResult - ) => - type.IsReferenceTypeOrNullableType() - .Should().Be(expectedResult); + ) => type.IsReferenceTypeOrNullableType().Should().Be(expectedResult); [Theory] [InlineData(typeof(ValueTuple), true)] @@ -117,12 +109,8 @@ bool expectedResult [InlineData(typeof(Entity), false)] [InlineData(typeof(Tuple), false)] [InlineData(typeof(Tuple), false)] - public void IsValueTupleType_ShouldDetermineWhetherTypeIsValueTupleType( - Type type, - bool expectedResult - ) => - type.IsValueTupleType() - .Should().Be(expectedResult); + public void IsValueTupleType_ShouldDetermineWhetherTypeIsValueTupleType(Type type, bool expectedResult) => + type.IsValueTupleType().Should().Be(expectedResult); [Fact] public void ShouldGuardAgainstNullArguments() diff --git a/tests/DbConnectionPlus.UnitTests/GlobalUsings.cs b/tests/DbConnectionPlus.UnitTests/GlobalUsings.cs index 878017e..e9bd802 100644 --- a/tests/DbConnectionPlus.UnitTests/GlobalUsings.cs +++ b/tests/DbConnectionPlus.UnitTests/GlobalUsings.cs @@ -3,12 +3,12 @@ global using System.ComponentModel.DataAnnotations.Schema; global using System.Data; global using System.Data.Common; -global using Xunit; global using AwesomeAssertions; +global using static AwesomeAssertions.FluentActions; global using Microsoft.Data.SqlClient; global using NSubstitute; global using RentADeveloper.ArgumentNullGuards; global using RentADeveloper.DbConnectionPlus.Configuration; -global using RentADeveloper.DbConnectionPlus.UnitTests.TestData; -global using static AwesomeAssertions.FluentActions; global using static RentADeveloper.DbConnectionPlus.DbConnectionExtensions; +global using RentADeveloper.DbConnectionPlus.UnitTests.TestData; +global using Xunit; diff --git a/tests/DbConnectionPlus.UnitTests/Helpers/NameHelperTests.cs b/tests/DbConnectionPlus.UnitTests/Helpers/NameHelperTests.cs index 55e8846..a615994 100644 --- a/tests/DbConnectionPlus.UnitTests/Helpers/NameHelperTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Helpers/NameHelperTests.cs @@ -22,7 +22,5 @@ public void CreateNameFromCallerArgumentExpression_ShouldCreateName( string expression, int maximumLength, string expectedName - ) => - NameHelper.CreateNameFromCallerArgumentExpression(expression, maximumLength) - .Should().Be(expectedName); + ) => NameHelper.CreateNameFromCallerArgumentExpression(expression, maximumLength).Should().Be(expectedName); } diff --git a/tests/DbConnectionPlus.UnitTests/Materializers/DataRowMaterializerTests.cs b/tests/DbConnectionPlus.UnitTests/Materializers/DataRowMaterializerTests.cs index facfb44..704acc6 100644 --- a/tests/DbConnectionPlus.UnitTests/Materializers/DataRowMaterializerTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Materializers/DataRowMaterializerTests.cs @@ -22,30 +22,24 @@ public void Materialize_ReturnsDataRowWithAllColumnsAndValues() dataReader .GetValues(Arg.Any()) .Returns(callInfo => - { - var array = callInfo.Arg(); - array[0] = value1; - array[1] = value2; - array[2] = value3; - return 3; - } - ); + { + var array = callInfo.Arg(); + array[0] = value1; + array[1] = value2; + array[2] = value3; + return 3; + }); var dataRow = DataRowMaterializer.Materialize(dataReader); - dataRow - .Should().Contain("ColumnA", value1); + dataRow.Should().Contain("ColumnA", value1); - dataRow - .Should().Contain("ColumnB", value2); + dataRow.Should().Contain("ColumnB", value2); - dataRow - .Should().Contain("ColumnC", value3); + dataRow.Should().Contain("ColumnC", value3); } [Fact] public void ShouldGuardAgainstNullArguments() => - ArgumentNullGuardVerifier.Verify(() => - DataRowMaterializer.Materialize(Substitute.For()) - ); + ArgumentNullGuardVerifier.Verify(() => DataRowMaterializer.Materialize(Substitute.For())); } diff --git a/tests/DbConnectionPlus.UnitTests/Materializers/EntityMaterializerFactoryTests.cs b/tests/DbConnectionPlus.UnitTests/Materializers/EntityMaterializerFactoryTests.cs index c69c1ad..f5df77e 100644 --- a/tests/DbConnectionPlus.UnitTests/Materializers/EntityMaterializerFactoryTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Materializers/EntityMaterializerFactoryTests.cs @@ -22,10 +22,11 @@ public void GetMaterializer_DataReaderFieldHasNoName_ShouldThrow() dataReader.GetName(0).Returns(string.Empty); Invoking(() => EntityMaterializerFactory.GetMaterializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The 1st column returned by the SQL statement does not have a name. Make sure that all columns the " + - "statement returns have a name.*" + "The 1st column returned by the SQL statement does not have a name. Make sure that all columns the " + + "statement returns have a name.*" ); } @@ -40,11 +41,12 @@ public void GetMaterializer_DataReaderFieldTypeNotCompatibleWithEntityPropertyTy dataReader.GetFieldType(0).Returns(typeof(Guid)); Invoking(() => EntityMaterializerFactory.GetMaterializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"The data type {typeof(Guid)} of the column 'CharValue' returned by the SQL statement is not " + - $"compatible with the property type {typeof(char)} of the corresponding property of the type " + - $"{typeof(Entity)}.*" + $"The data type {typeof(Guid)} of the column 'CharValue' returned by the SQL statement is not " + + $"compatible with the property type {typeof(char)} of the corresponding property of the type " + + $"{typeof(Entity)}.*" ); } @@ -56,7 +58,8 @@ public void GetMaterializer_DataReaderHasNoFields_ShouldThrow() dataReader.FieldCount.Returns(0); Invoking(() => EntityMaterializerFactory.GetMaterializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage("The SQL statement did not return any columns.*"); } @@ -74,10 +77,11 @@ public void GetMaterializer_NoFieldMatchesAWritableProperty_ShouldThrow() dataReader.GetFieldType(1).Returns(typeof(int)); Invoking(() => EntityMaterializerFactory.GetMaterializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "None of the 2 field(s) of the result set (NotAPropertyOfEntity, AlsoNotAPropertyOfEntity) could " + - $"be mapped to a writable property of the entity type {typeof(Entity)}.*" + "None of the 2 field(s) of the result set (NotAPropertyOfEntity, AlsoNotAPropertyOfEntity) could " + + $"be mapped to a writable property of the entity type {typeof(Entity)}.*" ); } @@ -94,8 +98,7 @@ public void GetMaterializer_SomeFieldsMatchAWritableProperty_ShouldNotThrow() dataReader.GetName(1).Returns("NotAPropertyOfEntity"); dataReader.GetFieldType(1).Returns(typeof(string)); - Invoking(() => EntityMaterializerFactory.GetMaterializer(dataReader)) - .Should().NotThrow(); + Invoking(() => EntityMaterializerFactory.GetMaterializer(dataReader)).Should().NotThrow(); } [Fact] @@ -108,19 +111,17 @@ public void GetMaterializer_DataReaderHasUnsupportedFieldType_ShouldThrow() dataReader.GetName(0).Returns("Value"); dataReader.GetFieldType(0).Returns(typeof(BigInteger)); - Invoking(() => - EntityMaterializerFactory.GetMaterializer(dataReader) - ) - .Should().Throw() + Invoking(() => EntityMaterializerFactory.GetMaterializer(dataReader)) + .Should() + .Throw() .WithMessage( - $"The data type {typeof(BigInteger)} of the column 'Value' returned by the SQL statement is not " + - "supported.*" + $"The data type {typeof(BigInteger)} of the column 'Value' returned by the SQL statement is not " + + "supported.*" ); } [Fact] - public void - Materializer_CharEntityProperty_DataReaderFieldContainsStringWithLengthNotOne_ShouldThrow() + public void Materializer_CharEntityProperty_DataReaderFieldContainsStringWithLengthNotOne_ShouldThrow() { var dataReader = Substitute.For(); @@ -134,37 +135,38 @@ public void var materializer = EntityMaterializerFactory.GetMaterializer(dataReader); Invoking(() => materializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(char)} of the corresponding property of the type " + - $"{typeof(Entity)}. See inner exception for details.*" + "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + + $"to the type {typeof(char)} of the corresponding property of the type " + + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException() .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly one " + - "character long." + $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly one " + + "character long." ); dataReader.GetString(0).Returns("ab"); Invoking(() => materializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(char)} of the corresponding property of the type " + - $"{typeof(Entity)}. See inner exception for details.*" + "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + + $"to the type {typeof(char)} of the corresponding property of the type " + + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + - "one character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + + "one character long." ); } [Fact] - public void - Materializer_CharEntityProperty_DataReaderFieldContainsStringWithLengthOne_ShouldGetFirstCharacter() + public void Materializer_CharEntityProperty_DataReaderFieldContainsStringWithLengthOne_ShouldGetFirstCharacter() { var dataReader = Substitute.For(); @@ -181,8 +183,7 @@ public void var entity = materializer(dataReader); - entity.CharValue - .Should().Be(character); + entity.CharValue.Should().Be(character); } [Fact] @@ -198,8 +199,7 @@ public void Materializer_CompatiblePrivateConstructor_ShouldUsePrivateConstructo var materializedEntity = materializer(dataReader); - materializedEntity - .Should().BeEquivalentTo(entities[0]); + materializedEntity.Should().BeEquivalentTo(entities[0]); } [Fact] @@ -215,8 +215,7 @@ public void Materializer_CompatiblePublicConstructor_ShouldUsePublicConstructor( var materializedEntity = materializer(dataReader); - materializedEntity - .Should().BeEquivalentTo(entities[0]); + materializedEntity.Should().BeEquivalentTo(entities[0]); } [Fact] @@ -235,8 +234,7 @@ public void Materializer_DataReaderFieldNameMatchesEntityPropertyCaseInsensitive var entity = materializer(dataReader); - entity.Id - .Should().Be(789); + entity.Id.Should().Be(789); } [Fact] @@ -263,11 +261,9 @@ public void Materializer_DataReaderHasCompatibleFieldTypes_ShouldConvertValues() var entity = materializer(dataReader); - entity.Id - .Should().Be(entityId); + entity.Id.Should().Be(entityId); - entity.Enum - .Should().Be(enumValue); + entity.Enum.Should().Be(enumValue); } [Fact] @@ -295,18 +291,16 @@ public void Materializer_EntityHasNoCorrespondingPropertyForDataReaderField_Shou dataReader.IsDBNull(2).Returns(false); dataReader.GetInt64(2).Returns(Generate.SmallNumber()); - var materializer = Invoking(() => - EntityMaterializerFactory.GetMaterializer(dataReader) - ) - .Should().NotThrow().Subject; + var materializer = Invoking(() => EntityMaterializerFactory.GetMaterializer(dataReader)) + .Should() + .NotThrow() + .Subject; var entity = materializer(dataReader); - entity.Id - .Should().Be(id); + entity.Id.Should().Be(id); - entity.Int32Value - .Should().Be(value); + entity.Int32Value.Should().Be(value); } [Fact] @@ -327,13 +321,11 @@ public void Materializer_EnumEntityProperty_DataReaderFieldContainsInteger_Shoul var entity = materializer(dataReader); - entity.Enum - .Should().Be(enumValue); + entity.Enum.Should().Be(enumValue); } [Fact] - public void - Materializer_EnumEntityProperty_DataReaderFieldContainsIntegerNotMatchingAnyEnumMemberValue_ShouldThrow() + public void Materializer_EnumEntityProperty_DataReaderFieldContainsIntegerNotMatchingAnyEnumMemberValue_ShouldThrow() { var dataReader = Substitute.For(); @@ -347,16 +339,17 @@ public void var materializer = EntityMaterializerFactory.GetMaterializer(dataReader); Invoking(() => materializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding property of the type " + - $"{typeof(EntityWithEnumStoredAsInteger)}. See inner exception for details.*" + "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding property of the type " + + $"{typeof(EntityWithEnumStoredAsInteger)}. See inner exception for details.*" ) .WithInnerException() .WithMessage( - $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + - $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); } @@ -378,8 +371,7 @@ public void Materializer_EnumEntityProperty_DataReaderFieldContainsString_Should var entity = materializer(dataReader); - entity.Enum - .Should().Be(enumValue); + entity.Enum.Should().Be(enumValue); } [Fact] @@ -397,16 +389,17 @@ public void Materializer_EnumEntityProperty_DataReaderFieldContainsStringNotMatc var materializer = EntityMaterializerFactory.GetMaterializer(dataReader); Invoking(() => materializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding property of the type " + - $"{typeof(EntityWithEnumStoredAsString)}. See inner exception for details.*" + "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding property of the type " + + $"{typeof(EntityWithEnumStoredAsString)}. See inner exception for details.*" ) .WithInnerException() .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. That " + - "string does not match any of the names of the enum's members.*" + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. That " + + "string does not match any of the names of the enum's members.*" ); } @@ -473,29 +466,21 @@ public void Materializer_Mapping_Attributes_ShouldUseAttributesMapping() _ = dataReader.DidNotReceive().IsDBNull(notMappedColumnOrdinal); _ = dataReader.DidNotReceive().GetString(notMappedColumnOrdinal); - materializedEntity.Computed_ - .Should().Be(entity.Computed_); + materializedEntity.Computed_.Should().Be(entity.Computed_); - materializedEntity.ConcurrencyToken_ - .Should().BeEquivalentTo(entity.ConcurrencyToken_); + materializedEntity.ConcurrencyToken_.Should().BeEquivalentTo(entity.ConcurrencyToken_); - materializedEntity.Identity_ - .Should().Be(entity.Identity_); + materializedEntity.Identity_.Should().Be(entity.Identity_); - materializedEntity.Key1_ - .Should().Be(entity.Key1_); + materializedEntity.Key1_.Should().Be(entity.Key1_); - materializedEntity.Key2_ - .Should().Be(entity.Key2_); + materializedEntity.Key2_.Should().Be(entity.Key2_); - materializedEntity.Value_ - .Should().Be(entity.Value_); + materializedEntity.Value_.Should().Be(entity.Value_); - materializedEntity.NotMapped - .Should().BeNull(); + materializedEntity.NotMapped.Should().BeNull(); - materializedEntity.RowVersion_ - .Should().BeEquivalentTo(entity.RowVersion_); + materializedEntity.RowVersion_.Should().BeEquivalentTo(entity.RowVersion_); } [Fact] @@ -563,29 +548,21 @@ public void Materializer_Mapping_FluentApi_ShouldUseFluentApiMapping() _ = dataReader.DidNotReceive().IsDBNull(notMappedColumnOrdinal); _ = dataReader.DidNotReceive().GetString(notMappedColumnOrdinal); - materializedEntity.Computed_ - .Should().Be(entity.Computed_); + materializedEntity.Computed_.Should().Be(entity.Computed_); - materializedEntity.ConcurrencyToken_ - .Should().BeEquivalentTo(entity.ConcurrencyToken_); + materializedEntity.ConcurrencyToken_.Should().BeEquivalentTo(entity.ConcurrencyToken_); - materializedEntity.Identity_ - .Should().Be(entity.Identity_); + materializedEntity.Identity_.Should().Be(entity.Identity_); - materializedEntity.Key1_ - .Should().Be(entity.Key1_); + materializedEntity.Key1_.Should().Be(entity.Key1_); - materializedEntity.Key2_ - .Should().Be(entity.Key2_); + materializedEntity.Key2_.Should().Be(entity.Key2_); - materializedEntity.Value_ - .Should().Be(entity.Value_); + materializedEntity.Value_.Should().Be(entity.Value_); - materializedEntity.NotMapped - .Should().BeNull(); + materializedEntity.NotMapped.Should().BeNull(); - materializedEntity.RowVersion_ - .Should().BeEquivalentTo(entity.RowVersion_); + materializedEntity.RowVersion_.Should().BeEquivalentTo(entity.RowVersion_); } [Fact] @@ -619,14 +596,11 @@ public void Materializer_Mapping_NoMapping_ShouldUseEntityTypeNameAndPropertyNam var materializedEntity = materializer(dataReader); - materializedEntity.Key1 - .Should().Be(entity.Key1); + materializedEntity.Key1.Should().Be(entity.Key1); - materializedEntity.Key2 - .Should().Be(entity.Key2); + materializedEntity.Key2.Should().Be(entity.Key2); - materializedEntity.Value - .Should().Be(entity.Value); + materializedEntity.Value.Should().Be(entity.Value); } [Fact] @@ -640,19 +614,19 @@ public void Materializer_NoCompatibleConstructor_NoParameterlessConstructor_Shou dataReader.GetFieldType(0).Returns(typeof(long)); Invoking(() => EntityMaterializerFactory.GetMaterializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"Could not materialize an instance of the type {typeof(EntityWithPublicConstructor)}. The type " + - "either needs to have a parameterless constructor or a constructor whose parameters match the " + - "columns returned by the SQL statement, e.g. a constructor that has the following " + - $"signature:{Environment.NewLine}" + - "(Int64 NonExistent).*" + $"Could not materialize an instance of the type {typeof(EntityWithPublicConstructor)}. The type " + + "either needs to have a parameterless constructor or a constructor whose parameters match the " + + "columns returned by the SQL statement, e.g. a constructor that has the following " + + $"signature:{Environment.NewLine}" + + "(Int64 NonExistent).*" ); } [Fact] - public void - Materializer_NoCompatibleConstructor_PrivateParameterlessConstructor_ShouldUsePrivateConstructorAndProperties() + public void Materializer_NoCompatibleConstructor_PrivateParameterlessConstructor_ShouldUsePrivateConstructorAndProperties() { var entities = Generate.Multiple(1); @@ -660,18 +634,17 @@ public void dataReader.Read(); - var materializer = - EntityMaterializerFactory.GetMaterializer(dataReader); + var materializer = EntityMaterializerFactory.GetMaterializer( + dataReader + ); var materializedEntity = materializer(dataReader); - materializedEntity - .Should().BeEquivalentTo(entities[0]); + materializedEntity.Should().BeEquivalentTo(entities[0]); } [Fact] - public void - Materializer_NoCompatibleConstructor_PublicParameterlessConstructor_ShouldUsePublicConstructorAndProperties() + public void Materializer_NoCompatibleConstructor_PublicParameterlessConstructor_ShouldUsePublicConstructorAndProperties() { var entities = Generate.Multiple(1); @@ -683,13 +656,11 @@ public void var materializedEntity = materializer(dataReader); - materializedEntity - .Should().BeEquivalentTo(entities[0]); + materializedEntity.Should().BeEquivalentTo(entities[0]); } [Fact] - public void - Materializer_NonNullableEntityProperty_DataReaderFieldContainsNull_ShouldThrow() + public void Materializer_NonNullableEntityProperty_DataReaderFieldContainsNull_ShouldThrow() { var dataReader = Substitute.For(); @@ -702,10 +673,11 @@ public void var materializer = EntityMaterializerFactory.GetMaterializer(dataReader); Invoking(() => materializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The column 'Id' returned by the SQL statement contains a NULL value, but the corresponding " + - $"property of the type {typeof(Entity)} is non-nullable.*" + "The column 'Id' returned by the SQL statement contains a NULL value, but the corresponding " + + $"property of the type {typeof(Entity)} is non-nullable.*" ); } @@ -721,14 +693,11 @@ public void Materializer_NullableEntityProperty_DataReaderFieldContainsNull_Shou dataReader.IsDBNull(0).Returns(true); dataReader.GetBoolean(0).Throws(new SqlNullValueException()); - var materializer = EntityMaterializerFactory - .GetMaterializer(dataReader); + var materializer = EntityMaterializerFactory.GetMaterializer(dataReader); - var entity = Invoking(() => materializer(dataReader)) - .Should().NotThrow().Subject; + var entity = Invoking(() => materializer(dataReader)).Should().NotThrow().Subject; - entity.NullableBooleanValue - .Should().BeNull(); + entity.NullableBooleanValue.Should().BeNull(); } [Fact] @@ -745,8 +714,7 @@ public void Materializer_PropertiesWithDifferentCasing_ShouldMatchPropertiesCase var materializedEntityWithDifferentCasingProperties = materializer(dataReader); - materializedEntityWithDifferentCasingProperties - .Should().BeEquivalentTo(entityWithDifferentCasingProperties); + materializedEntityWithDifferentCasingProperties.Should().BeEquivalentTo(entityWithDifferentCasingProperties); } [Fact] @@ -774,8 +742,7 @@ public void Materializer_ShouldMaterializeDateTimeOffsetValue() var materializedEntity = materializer(dataReader); - materializedEntity - .Should().BeEquivalentTo(entity); + materializedEntity.Should().BeEquivalentTo(entity); } [Fact] @@ -792,11 +759,9 @@ public void ReflectionMaterializer_ShouldMaterializeTheSameEntityAsTheExpression var materializedEntity = reflectionMaterializer(dataReader); - materializedEntity - .Should().BeEquivalentTo(entities[0]); + materializedEntity.Should().BeEquivalentTo(entities[0]); - materializedEntity - .Should().BeEquivalentTo(expressionMaterializer(dataReader)); + materializedEntity.Should().BeEquivalentTo(expressionMaterializer(dataReader)); } [Fact] @@ -832,14 +797,11 @@ public void ReflectionMaterializer_Mapping_Attributes_ShouldUseAttributesMapping _ = dataReader.DidNotReceive().IsDBNull(notMappedColumnOrdinal); _ = dataReader.DidNotReceive().GetString(notMappedColumnOrdinal); - materializedEntity.Key1_ - .Should().Be(entity.Key1_); + materializedEntity.Key1_.Should().Be(entity.Key1_); - materializedEntity.Value_ - .Should().Be(entity.Value_); + materializedEntity.Value_.Should().Be(entity.Value_); - materializedEntity.NotMapped - .Should().BeNull(); + materializedEntity.NotMapped.Should().BeNull(); } [Fact] @@ -856,8 +818,7 @@ public void ReflectionMaterializer_DataReaderFieldNameMatchesEntityPropertyCaseI var materializer = GetReflectionMaterializer(dataReader); - materializer(dataReader).Id - .Should().Be(789); + materializer(dataReader).Id.Should().Be(789); } [Fact] @@ -884,11 +845,9 @@ public void ReflectionMaterializer_DataReaderHasCompatibleFieldTypes_ShouldConve var entity = materializer(dataReader); - entity.Id - .Should().Be(entityId); + entity.Id.Should().Be(entityId); - entity.Enum - .Should().Be(enumValue); + entity.Enum.Should().Be(enumValue); } [Fact] @@ -906,16 +865,17 @@ public void ReflectionMaterializer_DataReaderFieldValueCannotBeConverted_ShouldT var materializer = GetReflectionMaterializer(dataReader); Invoking(() => materializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + - $"to the type {typeof(char)} of the corresponding property of the type " + - $"{typeof(Entity)}. See inner exception for details.*" + "The column 'CharValue' returned by the SQL statement contains a value that could not be converted " + + $"to the type {typeof(char)} of the corresponding property of the type " + + $"{typeof(Entity)}. See inner exception for details.*" ) .WithInnerException() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + - "one character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly " + + "one character long." ); } @@ -933,10 +893,11 @@ public void ReflectionMaterializer_NonNullableEntityProperty_DataReaderFieldCont var materializer = GetReflectionMaterializer(dataReader); Invoking(() => materializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The column 'Id' returned by the SQL statement contains a NULL value, but the corresponding " + - $"property of the type {typeof(Entity)} is non-nullable.*" + "The column 'Id' returned by the SQL statement contains a NULL value, but the corresponding " + + $"property of the type {typeof(Entity)} is non-nullable.*" ); } @@ -954,11 +915,9 @@ public void ReflectionMaterializer_NullableEntityProperty_DataReaderFieldContain var materializer = GetReflectionMaterializer(dataReader); - var entity = Invoking(() => materializer(dataReader)) - .Should().NotThrow().Subject; + var entity = Invoking(() => materializer(dataReader)).Should().NotThrow().Subject; - entity.NullableBooleanValue - .Should().BeNull(); + entity.NullableBooleanValue.Should().BeNull(); } [Fact] @@ -984,8 +943,7 @@ public void ReflectionMaterializer_ShouldMaterializeDateTimeOffsetValue() var materializer = GetReflectionMaterializer(dataReader); - materializer(dataReader) - .Should().BeEquivalentTo(entity); + materializer(dataReader).Should().BeEquivalentTo(entity); } [Fact] @@ -1002,11 +960,9 @@ public void ReflectionMaterializer_CompatiblePublicConstructor_ShouldUsePublicCo var materializedEntity = reflectionMaterializer(dataReader); - materializedEntity - .Should().BeEquivalentTo(entities[0]); + materializedEntity.Should().BeEquivalentTo(entities[0]); - materializedEntity - .Should().BeEquivalentTo(expressionMaterializer(dataReader)); + materializedEntity.Should().BeEquivalentTo(expressionMaterializer(dataReader)); } [Fact] @@ -1020,8 +976,7 @@ public void ReflectionMaterializer_CompatiblePrivateConstructor_ShouldUsePrivate var materializer = GetReflectionMaterializer(dataReader); - materializer(dataReader) - .Should().BeEquivalentTo(entities[0]); + materializer(dataReader).Should().BeEquivalentTo(entities[0]); } [Fact] @@ -1053,8 +1008,7 @@ public void ReflectionMaterializer_ConstructorParametersInADifferentOrderThanThe var materializer = GetReflectionMaterializer(dataReader); - materializer(dataReader) - .Should().Be(new Item(id, name, enumValue)); + materializer(dataReader).Should().Be(new Item(id, name, enumValue)); } [Fact] @@ -1065,18 +1019,20 @@ public void ReflectionMaterializer_NonNullableConstructorParameter_DataReaderFie dataReader.IsDBNull(0).Returns(true); var expectedMessage = - "The column 'Id' returned by the SQL statement contains a NULL value, but the corresponding property " + - $"of the type {typeof(Item)} is non-nullable.*"; + "The column 'Id' returned by the SQL statement contains a NULL value, but the corresponding property " + + $"of the type {typeof(Item)} is non-nullable.*"; var reflectionMaterializer = GetReflectionMaterializer(dataReader); var expressionMaterializer = EntityMaterializerFactory.GetMaterializer(dataReader); Invoking(() => reflectionMaterializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage(expectedMessage); Invoking(() => expressionMaterializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage(expectedMessage); } @@ -1089,8 +1045,7 @@ public void ReflectionMaterializer_NullableConstructorParameter_DataReaderFieldC var materializer = GetReflectionMaterializer(dataReader); - materializer(dataReader).Name - .Should().BeNull(); + materializer(dataReader).Name.Should().BeNull(); } [Fact] @@ -1101,25 +1056,27 @@ public void ReflectionMaterializer_ConstructorParameterValueCannotBeConverted_Sh dataReader.GetString(2).Returns("NonExistent"); var expectedMessage = - "The column 'Enum' returned by the SQL statement contains a value that could not be converted to the " + - $"type {typeof(TestEnum)} of the corresponding property of the type {typeof(Item)}. See inner " + - "exception for details.*"; + "The column 'Enum' returned by the SQL statement contains a value that could not be converted to the " + + $"type {typeof(TestEnum)} of the corresponding property of the type {typeof(Item)}. See inner " + + "exception for details.*"; var expectedInnerMessage = - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. That " + - "string does not match any of the names of the enum's members.*"; + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. That " + + "string does not match any of the names of the enum's members.*"; var reflectionMaterializer = GetReflectionMaterializer(dataReader); var expressionMaterializer = EntityMaterializerFactory.GetMaterializer(dataReader); Invoking(() => reflectionMaterializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage(expectedMessage) .WithInnerException() .WithMessage(expectedInnerMessage); Invoking(() => expressionMaterializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage(expectedMessage) .WithInnerException() .WithMessage(expectedInnerMessage); @@ -1136,8 +1093,7 @@ public void ReflectionMaterializer_PrivateParameterlessConstructor_ShouldUsePriv var materializer = GetReflectionMaterializer(dataReader); - materializer(dataReader) - .Should().BeEquivalentTo(entities[0]); + materializer(dataReader).Should().BeEquivalentTo(entities[0]); } [Fact] diff --git a/tests/DbConnectionPlus.UnitTests/Materializers/MaterializerFactoryHelperTests.cs b/tests/DbConnectionPlus.UnitTests/Materializers/MaterializerFactoryHelperTests.cs index 0ce6f2b..fc15492 100644 --- a/tests/DbConnectionPlus.UnitTests/Materializers/MaterializerFactoryHelperTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Materializers/MaterializerFactoryHelperTests.cs @@ -20,8 +20,7 @@ public void CreateGetDbDataReaderFieldValueExpression_BytesFieldType_ShouldCallG typeof(byte[]) ); - expression.ToString() - .Should().Match("Convert(*DbDataReader*.GetValue(1), Byte[])"); + expression.ToString().Should().Match("Convert(*DbDataReader*.GetValue(1), Byte[])"); } [Fact] @@ -37,8 +36,7 @@ public void CreateGetDbDataReaderFieldValueExpression_DateOnlyFieldType_ShouldCa typeof(DateOnly) ); - expression.ToString() - .Should().Match("Convert(*DbDataReader*.GetValue(1), DateOnly)"); + expression.ToString().Should().Match("Convert(*DbDataReader*.GetValue(1), DateOnly)"); } [Fact] @@ -54,8 +52,7 @@ public void CreateGetDbDataReaderFieldValueExpression_DateTimeOffsetFieldType_Sh typeof(DateTimeOffset) ); - expression.ToString() - .Should().Match("Convert(*DbDataReader*.GetValue(1), DateTimeOffset)"); + expression.ToString().Should().Match("Convert(*DbDataReader*.GetValue(1), DateTimeOffset)"); } [Theory] @@ -85,8 +82,7 @@ string expectedExpression fieldType ); - expression.ToString() - .Should().Match(expectedExpression); + expression.ToString().Should().Match(expectedExpression); } [Fact] @@ -102,8 +98,7 @@ public void CreateGetDbDataReaderFieldValueExpression_TimeOnlyFieldType_ShouldCa typeof(TimeOnly) ); - expression.ToString() - .Should().Match("Convert(*DbDataReader*.GetValue(1), TimeOnly)"); + expression.ToString().Should().Match("Convert(*DbDataReader*.GetValue(1), TimeOnly)"); } [Fact] @@ -119,8 +114,7 @@ public void CreateGetDbDataReaderFieldValueExpression_TimeSpanFieldType_ShouldCa typeof(TimeSpan) ); - expression.ToString() - .Should().Match("Convert(*DbDataReader*.GetValue(1), TimeSpan)"); + expression.ToString().Should().Match("Convert(*DbDataReader*.GetValue(1), TimeSpan)"); } [Fact] @@ -128,7 +122,8 @@ public void CreateGetDbDataReaderFieldValueExpression_UnsupportedFieldType_Shoul { var dataReader = Substitute.For(); - Invoking(() => MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueExpression( + Invoking(() => + MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueExpression( Expression.Constant(dataReader), Expression.Constant(1), 1, @@ -136,13 +131,15 @@ public void CreateGetDbDataReaderFieldValueExpression_UnsupportedFieldType_Shoul typeof(BigInteger) ) ) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"The data type {typeof(BigInteger)} of the column 'FieldA' returned by the SQL statement is not " + - "supported.*" + $"The data type {typeof(BigInteger)} of the column 'FieldA' returned by the SQL statement is not " + + "supported.*" ); - Invoking(() => MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueExpression( + Invoking(() => + MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueExpression( Expression.Constant(dataReader), Expression.Constant(1), 1, @@ -150,10 +147,11 @@ public void CreateGetDbDataReaderFieldValueExpression_UnsupportedFieldType_Shoul typeof(BigInteger) ) ) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"The data type {typeof(BigInteger)} of the 2nd column returned by the SQL statement is not " + - "supported.*" + $"The data type {typeof(BigInteger)} of the 2nd column returned by the SQL statement is not " + + "supported.*" ); } @@ -181,7 +179,8 @@ string expectedDbDataReaderMethodName { var dataReader = Substitute.For(); - MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueExpression( + MaterializerFactoryHelper + .CreateGetDbDataReaderFieldValueExpression( Expression.Constant(dataReader), Expression.Constant(1), 1, @@ -189,39 +188,37 @@ string expectedDbDataReaderMethodName fieldType ) .ToString() - .Should().Contain($".{expectedDbDataReaderMethodName}(1)"); + .Should() + .Contain($".{expectedDbDataReaderMethodName}(1)"); _ = MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueFunction(1, "FieldA", fieldType)(dataReader); - dataReader.ReceivedCalls().Select(call => call.GetMethodInfo().Name) - .Should().Equal(expectedDbDataReaderMethodName); + dataReader + .ReceivedCalls() + .Select(call => call.GetMethodInfo().Name) + .Should() + .Equal(expectedDbDataReaderMethodName); } [Fact] public void CreateGetDbDataReaderFieldValueFunction_UnsupportedFieldType_ShouldThrow() { - Invoking(() => MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueFunction( - 1, - "FieldA", - typeof(BigInteger) - ) + Invoking(() => + MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueFunction(1, "FieldA", typeof(BigInteger)) ) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"The data type {typeof(BigInteger)} of the column 'FieldA' returned by the SQL statement is not " + - "supported.*" + $"The data type {typeof(BigInteger)} of the column 'FieldA' returned by the SQL statement is not " + + "supported.*" ); - Invoking(() => MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueFunction( - 1, - "", - typeof(BigInteger) - ) - ) - .Should().Throw() + Invoking(() => MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueFunction(1, "", typeof(BigInteger))) + .Should() + .Throw() .WithMessage( - $"The data type {typeof(BigInteger)} of the 2nd column returned by the SQL statement is not " + - "supported.*" + $"The data type {typeof(BigInteger)} of the 2nd column returned by the SQL statement is not " + + "supported.*" ); } @@ -230,14 +227,15 @@ public void DbDataReaderGetValueMethod_ShouldReferenceDbDataReaderGetValue() { var method = MaterializerFactoryHelper.DbDataReaderGetValueMethod; - method.DeclaringType - .Should().Be(typeof(DbDataReader)); + method.DeclaringType.Should().Be(typeof(DbDataReader)); - method.Name - .Should().Be(nameof(DbDataReader.GetValue)); + method.Name.Should().Be(nameof(DbDataReader.GetValue)); - method.GetParameters().Select(p => (p.Name, p.ParameterType)) - .Should().BeEquivalentTo([("ordinal", typeof(int))]); + method + .GetParameters() + .Select(p => (p.Name, p.ParameterType)) + .Should() + .BeEquivalentTo([("ordinal", typeof(int))]); } [Fact] @@ -245,14 +243,15 @@ public void DbDataReaderIsDBNullMethod_ShouldReferenceDbDataReaderIsDBNull() { var method = MaterializerFactoryHelper.DbDataReaderIsDBNullMethod; - method.DeclaringType - .Should().Be(typeof(DbDataReader)); + method.DeclaringType.Should().Be(typeof(DbDataReader)); - method.Name - .Should().Be(nameof(DbDataReader.IsDBNull)); + method.Name.Should().Be(nameof(DbDataReader.IsDBNull)); - method.GetParameters().Select(p => (p.Name, p.ParameterType)) - .Should().BeEquivalentTo([("ordinal", typeof(int))]); + method + .GetParameters() + .Select(p => (p.Name, p.ParameterType)) + .Should() + .BeEquivalentTo([("ordinal", typeof(int))]); } [Theory] @@ -277,26 +276,20 @@ public void DbDataReaderIsDBNullMethod_ShouldReferenceDbDataReaderIsDBNull() public void IsDbDataReaderTypedGetMethodAvailable_ShouldReturnWhetherTypedGetMethodIsAvailable( Type fieldType, bool expectedResult - ) => - MaterializerFactoryHelper.IsDbDataReaderTypedGetMethodAvailable(fieldType) - .Should().Be(expectedResult); + ) => MaterializerFactoryHelper.IsDbDataReaderTypedGetMethodAvailable(fieldType).Should().Be(expectedResult); [Fact] public void MakeValueConverterConvertValueToTypeMethod_ShouldReferenceValueConverterConvertValueToType() { var method = MaterializerFactoryHelper.MakeValueConverterConvertValueToTypeMethod(typeof(int)); - method.DeclaringType - .Should().Be(typeof(ValueConverter)); + method.DeclaringType.Should().Be(typeof(ValueConverter)); - method.Name - .Should().Be(nameof(ValueConverter.ConvertValueToType)); + method.Name.Should().Be(nameof(ValueConverter.ConvertValueToType)); - method.GetGenericArguments() - .Should().Equal(typeof(int)); + method.GetGenericArguments().Should().Equal(typeof(int)); - method.GetParameters().Select(p => (p.Name, p.ParameterType)) - .Should().Equal(("value", typeof(object))); + method.GetParameters().Select(p => (p.Name, p.ParameterType)).Should().Equal(("value", typeof(object))); } [Fact] @@ -315,17 +308,11 @@ public void ShouldGuardAgainstNullArguments() ); ArgumentNullGuardVerifier.Verify(() => - MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueFunction( - 1, - "FieldA", - typeof(int) - ) + MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueFunction(1, "FieldA", typeof(int)) ); ArgumentNullGuardVerifier.Verify(() => - MaterializerFactoryHelper.IsDbDataReaderTypedGetMethodAvailable( - typeof(int) - ) + MaterializerFactoryHelper.IsDbDataReaderTypedGetMethodAvailable(typeof(int)) ); } @@ -334,14 +321,11 @@ public void StringCharsProperty_ShouldReferenceStringCharsIndexer() { var property = MaterializerFactoryHelper.StringCharsProperty; - property.DeclaringType - .Should().Be(typeof(string)); + property.DeclaringType.Should().Be(typeof(string)); - property.Name - .Should().Be("Chars"); + property.Name.Should().Be("Chars"); - property.PropertyType - .Should().Be(typeof(char)); + property.PropertyType.Should().Be(typeof(char)); } [Fact] @@ -349,17 +333,17 @@ public void StringConcatMethod_ShouldReferenceStringConcatWithThreeStringParamet { var method = MaterializerFactoryHelper.StringConcatMethod; - method.DeclaringType - .Should().Be(typeof(string)); + method.DeclaringType.Should().Be(typeof(string)); - method.Name - .Should().Be(nameof(String.Concat)); + method.Name.Should().Be(nameof(String.Concat)); - method.GetParameters().Select(p => (p.Name, p.ParameterType)) - .Should().Equal(("str0", typeof(string)), ("str1", typeof(string)), ("str2", typeof(string))); + method + .GetParameters() + .Select(p => (p.Name, p.ParameterType)) + .Should() + .Equal(("str0", typeof(string)), ("str1", typeof(string)), ("str2", typeof(string))); - method.ReturnType - .Should().Be(typeof(string)); + method.ReturnType.Should().Be(typeof(string)); } [Fact] @@ -367,13 +351,10 @@ public void StringLengthProperty_ShouldReferenceStringLengthProperty() { var property = MaterializerFactoryHelper.StringLengthProperty; - property.DeclaringType - .Should().Be(typeof(string)); + property.DeclaringType.Should().Be(typeof(string)); - property.Name - .Should().Be(nameof(String.Length)); + property.Name.Should().Be(nameof(String.Length)); - property.PropertyType - .Should().Be(typeof(int)); + property.PropertyType.Should().Be(typeof(int)); } } diff --git a/tests/DbConnectionPlus.UnitTests/Materializers/ValueTupleMaterializerFactoryTests.cs b/tests/DbConnectionPlus.UnitTests/Materializers/ValueTupleMaterializerFactoryTests.cs index ff189d9..edd1e6a 100644 --- a/tests/DbConnectionPlus.UnitTests/Materializers/ValueTupleMaterializerFactoryTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Materializers/ValueTupleMaterializerFactoryTests.cs @@ -17,17 +17,17 @@ public void GetMaterializer_DataReaderFieldCountDoesNotMatchValueTupleFieldCount dataReader.FieldCount.Returns(2); Invoking(() => ValueTupleMaterializerFactory.GetMaterializer<(int, int, int)>(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"The SQL statement returned 2 columns, but the value tuple type {typeof((int, int, int))} has " + - "3 fields. Make sure that the SQL statement returns the same number of columns as the number of " + - "fields in the value tuple type.*" + $"The SQL statement returned 2 columns, but the value tuple type {typeof((int, int, int))} has " + + "3 fields. Make sure that the SQL statement returns the same number of columns as the number of " + + "fields in the value tuple type.*" ); } [Fact] - public void - GetMaterializer_DataReaderFieldTypeNotCompatibleWithValueTupleFieldType_ShouldThrow() + public void GetMaterializer_DataReaderFieldTypeNotCompatibleWithValueTupleFieldType_ShouldThrow() { var dataReader = Substitute.For(); @@ -37,11 +37,12 @@ public void dataReader.GetFieldType(0).Returns(typeof(Guid)); Invoking(() => ValueTupleMaterializerFactory.GetMaterializer>(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"The data type {typeof(Guid)} of the column 'DateTime' returned by the SQL statement is not " + - $"compatible with the field type {typeof(DateTime)} of the corresponding field of the value tuple " + - $"type {typeof(ValueTuple)}.*" + $"The data type {typeof(Guid)} of the column 'DateTime' returned by the SQL statement is not " + + $"compatible with the field type {typeof(DateTime)} of the corresponding field of the value tuple " + + $"type {typeof(ValueTuple)}.*" ); dataReader.FieldCount.Returns(1); @@ -50,11 +51,12 @@ public void dataReader.GetFieldType(0).Returns(typeof(Guid)); Invoking(() => ValueTupleMaterializerFactory.GetMaterializer>(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"The data type {typeof(Guid)} of the 1st column returned by the SQL statement is not " + - $"compatible with the field type {typeof(DateTime)} of the corresponding field of the value tuple " + - $"type {typeof(ValueTuple)}.*" + $"The data type {typeof(Guid)} of the 1st column returned by the SQL statement is not " + + $"compatible with the field type {typeof(DateTime)} of the corresponding field of the value tuple " + + $"type {typeof(ValueTuple)}.*" ); } @@ -66,7 +68,8 @@ public void GetMaterializer_DataReaderHasNoFields_ShouldThrow() dataReader.FieldCount.Returns(0); Invoking(() => ValueTupleMaterializerFactory.GetMaterializer>(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage("The SQL statement did not return any columns.*"); } @@ -81,10 +84,11 @@ public void GetMaterializer_DataReaderHasUnsupportedFieldType_ShouldThrow() dataReader.GetFieldType(0).Returns(typeof(BigInteger)); Invoking(() => ValueTupleMaterializerFactory.GetMaterializer>(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - $"The data type {typeof(BigInteger)} of the column 'Value' returned by the SQL statement is not " + - "supported.*" + $"The data type {typeof(BigInteger)} of the column 'Value' returned by the SQL statement is not " + + "supported.*" ); dataReader.FieldCount.Returns(1); @@ -93,7 +97,8 @@ public void GetMaterializer_DataReaderHasUnsupportedFieldType_ShouldThrow() dataReader.GetFieldType(0).Returns(typeof(BigInteger)); Invoking(() => ValueTupleMaterializerFactory.GetMaterializer>(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( $"The data type {typeof(BigInteger)} of the 1st column returned by the SQL statement is not supported.*" ); @@ -105,10 +110,9 @@ public void GetMaterializer_TypeIsNotAValueTupleType_ShouldThrow() var dataReader = Substitute.For(); Invoking(() => ValueTupleMaterializerFactory.GetMaterializer(dataReader)) - .Should().Throw() - .WithMessage( - $"The specified type {typeof(NotAValueTuple)} is not a {typeof(ValueTuple)} type.*" - ); + .Should() + .Throw() + .WithMessage($"The specified type {typeof(NotAValueTuple)} is not a {typeof(ValueTuple)} type.*"); } [Fact] @@ -135,11 +139,9 @@ public void Materializer_DataReaderHasCompatibleFieldTypes_ShouldConvertValues() var entity = materializer(dataReader); - entity.Id - .Should().Be(entityId); + entity.Id.Should().Be(entityId); - entity.Enum - .Should().Be(enumValue); + entity.Enum.Should().Be(enumValue); } [Fact] @@ -160,8 +162,7 @@ public void Materializer_EnumValueTupleField_DataReaderContainsInteger_ShouldCon var valueTuple = materializer(dataReader); - valueTuple.Item1 - .Should().Be(enumValue); + valueTuple.Item1.Should().Be(enumValue); } [Fact] @@ -176,20 +177,20 @@ public void Materializer_EnumValueTupleField_DataReaderContainsIntegerNotMatchin dataReader.IsDBNull(0).Returns(false); dataReader.GetInt32(0).Returns(999); - var materializer = ValueTupleMaterializerFactory - .GetMaterializer>(dataReader); + var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); Invoking(() => materializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException() .WithMessage( - $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + - $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); } @@ -207,13 +208,11 @@ public void Materializer_EnumValueTupleField_DataReaderContainsString_ShouldConv dataReader.IsDBNull(0).Returns(false); dataReader.GetString(0).Returns(enumValue.ToString()); - var materializer = ValueTupleMaterializerFactory - .GetMaterializer>(dataReader); + var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); var valueTuple = materializer(dataReader); - valueTuple.Item1 - .Should().Be(enumValue); + valueTuple.Item1.Should().Be(enumValue); } [Fact] @@ -228,20 +227,20 @@ public void Materializer_EnumValueTupleField_DataReaderContainsStringNotMatching dataReader.IsDBNull(0).Returns(false); dataReader.GetString(0).Returns("NonExistent"); - var materializer = ValueTupleMaterializerFactory - .GetMaterializer>(dataReader); + var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); Invoking(() => materializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException() .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. That " + - "string does not match any of the names of the enum's members.*" + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. That " + + "string does not match any of the names of the enum's members.*" ); } @@ -260,64 +259,59 @@ public void Materializer_MoreThan7FieldsValueTupleType_ShouldMaterializeNestedVa dataReader.GetInt32(i).Returns(i + 1); } - var materializer = ValueTupleMaterializerFactory - .GetMaterializer<( - int, int, int, int, int, int, int, - int, int, int, int, int, int, int, - int - )>(dataReader); + var materializer = ValueTupleMaterializerFactory.GetMaterializer<( + int, + int, + int, + int, + int, + int, + int, + int, + int, + int, + int, + int, + int, + int, + int + )>(dataReader); var valueTuple = materializer(dataReader); - valueTuple.Item1 - .Should().Be(1); + valueTuple.Item1.Should().Be(1); - valueTuple.Item2 - .Should().Be(2); + valueTuple.Item2.Should().Be(2); - valueTuple.Item3 - .Should().Be(3); + valueTuple.Item3.Should().Be(3); - valueTuple.Item4 - .Should().Be(4); + valueTuple.Item4.Should().Be(4); - valueTuple.Item5 - .Should().Be(5); + valueTuple.Item5.Should().Be(5); - valueTuple.Item6 - .Should().Be(6); + valueTuple.Item6.Should().Be(6); - valueTuple.Item7 - .Should().Be(7); + valueTuple.Item7.Should().Be(7); - valueTuple.Rest.Item1 - .Should().Be(8); + valueTuple.Rest.Item1.Should().Be(8); - valueTuple.Rest.Item2 - .Should().Be(9); + valueTuple.Rest.Item2.Should().Be(9); - valueTuple.Rest.Item3 - .Should().Be(10); + valueTuple.Rest.Item3.Should().Be(10); - valueTuple.Rest.Item4 - .Should().Be(11); + valueTuple.Rest.Item4.Should().Be(11); - valueTuple.Rest.Item5 - .Should().Be(12); + valueTuple.Rest.Item5.Should().Be(12); - valueTuple.Rest.Item6 - .Should().Be(13); + valueTuple.Rest.Item6.Should().Be(13); - valueTuple.Rest.Item7 - .Should().Be(14); + valueTuple.Rest.Item7.Should().Be(14); - valueTuple.Rest.Rest.Item1 - .Should().Be(15); + valueTuple.Rest.Rest.Item1.Should().Be(15); } [Fact] - public void - Materializer_NonNullableCharValueTupleField_DataReaderFieldContainsStringWithLengthNotOne_ShouldThrow() + public void Materializer_NonNullableCharValueTupleField_DataReaderFieldContainsStringWithLengthNotOne_ShouldThrow() { var dataReader = Substitute.For(); @@ -331,37 +325,38 @@ public void var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); Invoking(() => materializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The column 'Char' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Char' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException() .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly one " + - "character long." + $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly one " + + "character long." ); dataReader.GetString(0).Returns("ab"); Invoking(() => materializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The column 'Char' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(char)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Char' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(char)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly one " + - "character long." + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly one " + + "character long." ); } [Fact] - public void - Materializer_NonNullableCharValueTupleField_DataReaderFieldContainsStringWithLengthOne_ShouldGetFirstCharacter() + public void Materializer_NonNullableCharValueTupleField_DataReaderFieldContainsStringWithLengthOne_ShouldGetFirstCharacter() { var dataReader = Substitute.For(); @@ -378,8 +373,7 @@ public void var valueTuple = materializer(dataReader); - valueTuple.Item1 - .Should().Be(character); + valueTuple.Item1.Should().Be(character); } [Fact] @@ -396,16 +390,16 @@ public void Materializer_NonNullableValueTupleField_DataReaderFieldContainsNull_ var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); Invoking(() => materializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The column 'Id' returned by the SQL statement contains a NULL value, but the corresponding field " + - $"of the value tuple type {typeof(ValueTuple)} is non-nullable.*" + "The column 'Id' returned by the SQL statement contains a NULL value, but the corresponding field " + + $"of the value tuple type {typeof(ValueTuple)} is non-nullable.*" ); } [Fact] - public void - Materializer_NullableCharValueTupleField_DataReaderFieldContainsStringWithLengthNotOne_ShouldThrow() + public void Materializer_NullableCharValueTupleField_DataReaderFieldContainsStringWithLengthNotOne_ShouldThrow() { var dataReader = Substitute.For(); @@ -419,37 +413,38 @@ public void var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); Invoking(() => materializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The column 'Char' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(char?)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Char' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(char?)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException() .WithMessage( - $"Could not convert the string '' to the type {typeof(char?)}. The string must be exactly one " + - "character long." + $"Could not convert the string '' to the type {typeof(char?)}. The string must be exactly one " + + "character long." ); dataReader.GetString(0).Returns("ab"); Invoking(() => materializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The column 'Char' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(char?)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Char' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(char?)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException() .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char?)}. The string must be exactly " + - "one character long." + $"Could not convert the string 'ab' to the type {typeof(char?)}. The string must be exactly " + + "one character long." ); } [Fact] - public void - Materializer_NullableCharValueTupleField_DataReaderFieldContainsStringWithLengthOne_ShouldGetFirstCharacter() + public void Materializer_NullableCharValueTupleField_DataReaderFieldContainsStringWithLengthOne_ShouldGetFirstCharacter() { var dataReader = Substitute.For(); @@ -466,8 +461,7 @@ public void var valueTuple = materializer(dataReader); - valueTuple.Item1 - .Should().Be(character); + valueTuple.Item1.Should().Be(character); } [Fact] @@ -484,11 +478,9 @@ public void Materializer_NullableValueTupleField_DataReaderFieldContainsNull_Sho var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); - var valueTuple = Invoking(() => materializer(dataReader)) - .Should().NotThrow().Subject; + var valueTuple = Invoking(() => materializer(dataReader)).Should().NotThrow().Subject; - valueTuple.Item1 - .Should().BeNull(); + valueTuple.Item1.Should().BeNull(); } [Fact] @@ -542,31 +534,31 @@ public void Materializer_ShouldMaterialize() dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt32(ordinal).Returns(entity.Int32Value); - var materializer = ValueTupleMaterializerFactory - .GetMaterializer<(bool, char, DateTime, decimal?, TestEnum, Guid, int)>(dataReader); + var materializer = ValueTupleMaterializerFactory.GetMaterializer<( + bool, + char, + DateTime, + decimal?, + TestEnum, + Guid, + int + )>(dataReader); var valueTuple = materializer(dataReader); - valueTuple.Item1 - .Should().Be(entity.BooleanValue); + valueTuple.Item1.Should().Be(entity.BooleanValue); - valueTuple.Item2 - .Should().Be(entity.CharValue); + valueTuple.Item2.Should().Be(entity.CharValue); - valueTuple.Item3 - .Should().Be(entity.DateTimeValue); + valueTuple.Item3.Should().Be(entity.DateTimeValue); - valueTuple.Item4 - .Should().BeNull(); + valueTuple.Item4.Should().BeNull(); - valueTuple.Item5 - .Should().Be(entity.EnumValue); + valueTuple.Item5.Should().Be(entity.EnumValue); - valueTuple.Item6 - .Should().Be(entity.GuidValue); + valueTuple.Item6.Should().Be(entity.GuidValue); - valueTuple.Item7 - .Should().Be(entity.Int32Value); + valueTuple.Item7.Should().Be(entity.Int32Value); } [Fact] @@ -587,8 +579,7 @@ public void Materializer_ShouldMaterializeBinaryData() var valueTuple = materializer(dataReader); - valueTuple.Item1 - .Should().BeEquivalentTo(bytes); + valueTuple.Item1.Should().BeEquivalentTo(bytes); } [Fact] @@ -605,13 +596,11 @@ public void Materializer_ShouldSupportSingleFieldValueTupleType() dataReader.IsDBNull(0).Returns(false); dataReader.GetBoolean(0).Returns(entity.BooleanValue); - var materializer = ValueTupleMaterializerFactory - .GetMaterializer>(dataReader); + var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); var valueTuple = materializer(dataReader); - valueTuple.Item1 - .Should().Be(entity.BooleanValue); + valueTuple.Item1.Should().Be(entity.BooleanValue); } [Fact] @@ -665,16 +654,25 @@ public void ReflectionMaterializer_ShouldMaterializeTheSameValueTupleAsTheExpres dataReader.IsDBNull(ordinal).Returns(false); dataReader.GetInt32(ordinal).Returns(entity.Int32Value); - var expressionMaterializer = ValueTupleMaterializerFactory - .GetMaterializer<(bool, char, DateTime, decimal?, TestEnum, Guid, int)>(dataReader); + var expressionMaterializer = ValueTupleMaterializerFactory.GetMaterializer<( + bool, + char, + DateTime, + decimal?, + TestEnum, + Guid, + int + )>(dataReader); - var reflectionMaterializer = - GetReflectionMaterializer<(bool, char, DateTime, decimal?, TestEnum, Guid, int)>(dataReader); + var reflectionMaterializer = GetReflectionMaterializer<(bool, char, DateTime, decimal?, TestEnum, Guid, int)>( + dataReader + ); var valueTuple = reflectionMaterializer(dataReader); valueTuple - .Should().Be( + .Should() + .Be( ( entity.BooleanValue, entity.CharValue, @@ -686,8 +684,7 @@ public void ReflectionMaterializer_ShouldMaterializeTheSameValueTupleAsTheExpres ) ); - valueTuple - .Should().Be(expressionMaterializer(dataReader)); + valueTuple.Should().Be(expressionMaterializer(dataReader)); } [Fact] @@ -705,30 +702,50 @@ public void ReflectionMaterializer_MoreThan7FieldsValueTupleType_ShouldMateriali dataReader.GetInt32(i).Returns(i + 1); } - var expressionMaterializer = ValueTupleMaterializerFactory - .GetMaterializer<( - int, int, int, int, int, int, int, - int, int, int, int, int, int, int, - int - )>(dataReader); + var expressionMaterializer = ValueTupleMaterializerFactory.GetMaterializer<( + int, + int, + int, + int, + int, + int, + int, + int, + int, + int, + int, + int, + int, + int, + int + )>(dataReader); var reflectionMaterializer = GetReflectionMaterializer<( - int, int, int, int, int, int, int, - int, int, int, int, int, int, int, + int, + int, + int, + int, + int, + int, + int, + int, + int, + int, + int, + int, + int, + int, int - )>(dataReader); + )>(dataReader); var valueTuple = reflectionMaterializer(dataReader); - valueTuple - .Should().Be((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)); + valueTuple.Should().Be((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)); - valueTuple - .Should().Be(expressionMaterializer(dataReader)); + valueTuple.Should().Be(expressionMaterializer(dataReader)); // The innermost value tuple is the one that only carries the 15th field. - valueTuple.Rest.Rest.Item1 - .Should().Be(15); + valueTuple.Rest.Rest.Item1.Should().Be(15); } [Fact] @@ -746,11 +763,9 @@ public void ReflectionMaterializer_EightFieldsValueTupleType_ShouldMaterializeNe dataReader.GetInt32(i).Returns(i + 1); } - var materializer = - GetReflectionMaterializer<(int, int, int, int, int, int, int, int)>(dataReader); + var materializer = GetReflectionMaterializer<(int, int, int, int, int, int, int, int)>(dataReader); - materializer(dataReader) - .Should().Be((1, 2, 3, 4, 5, 6, 7, 8)); + materializer(dataReader).Should().Be((1, 2, 3, 4, 5, 6, 7, 8)); } [Fact] @@ -777,11 +792,9 @@ public void ReflectionMaterializer_DataReaderHasCompatibleFieldTypes_ShouldConve var valueTuple = materializer(dataReader); - valueTuple.Id - .Should().Be(entityId); + valueTuple.Id.Should().Be(entityId); - valueTuple.Enum - .Should().Be(enumValue); + valueTuple.Enum.Should().Be(enumValue); } [Fact] @@ -800,8 +813,7 @@ public void ReflectionMaterializer_ShouldMaterializeBinaryData() var materializer = GetReflectionMaterializer>(dataReader); - materializer(dataReader).Item1 - .Should().BeEquivalentTo(bytes); + materializer(dataReader).Item1.Should().BeEquivalentTo(bytes); } [Fact] @@ -819,16 +831,19 @@ public void ReflectionMaterializer_NonNullableValueTupleField_DataReaderFieldCon var reflectionMaterializer = GetReflectionMaterializer>(dataReader); var expectedMessage = Invoking(() => expressionMaterializer(dataReader)) - .Should().Throw().Which.Message; + .Should() + .Throw() + .Which.Message; Invoking(() => reflectionMaterializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The column 'Id' returned by the SQL statement contains a NULL value, but the corresponding field " + - $"of the value tuple type {typeof(ValueTuple)} is non-nullable." + "The column 'Id' returned by the SQL statement contains a NULL value, but the corresponding field " + + $"of the value tuple type {typeof(ValueTuple)} is non-nullable." ) - .And.Message - .Should().Be(expectedMessage); + .And.Message.Should() + .Be(expectedMessage); } [Fact] @@ -845,9 +860,7 @@ public void ReflectionMaterializer_NullableValueTupleField_DataReaderFieldContai var materializer = GetReflectionMaterializer>(dataReader); - Invoking(() => materializer(dataReader)) - .Should().NotThrow().Subject.Item1 - .Should().BeNull(); + Invoking(() => materializer(dataReader)).Should().NotThrow().Subject.Item1.Should().BeNull(); } [Fact] @@ -866,24 +879,29 @@ public void ReflectionMaterializer_DataReaderFieldValueCannotBeConverted_ShouldT var reflectionMaterializer = GetReflectionMaterializer>(dataReader); var expectedMessage = Invoking(() => expressionMaterializer(dataReader)) - .Should().Throw().Which.Message; + .Should() + .Throw() + .Which.Message; Invoking(() => reflectionMaterializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + - $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + - $"{typeof(ValueTuple)}. See inner exception for details.*" + "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" ) .WithInnerException() .WithMessage( - $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + - $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); Invoking(() => reflectionMaterializer(dataReader)) - .Should().Throw().Which.Message - .Should().Be(expectedMessage); + .Should() + .Throw() + .Which.Message.Should() + .Be(expectedMessage); } [Fact] @@ -906,16 +924,19 @@ public void ReflectionMaterializer_DataReaderFieldHasNoName_ShouldReportThePosit var reflectionMaterializer = GetReflectionMaterializer<(long, long)>(dataReader); var expectedMessage = Invoking(() => expressionMaterializer(dataReader)) - .Should().Throw().Which.Message; + .Should() + .Throw() + .Which.Message; Invoking(() => reflectionMaterializer(dataReader)) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The 2nd column returned by the SQL statement contains a NULL value, but the corresponding field " + - $"of the value tuple type {typeof((long, long))} is non-nullable." + "The 2nd column returned by the SQL statement contains a NULL value, but the corresponding field " + + $"of the value tuple type {typeof((long, long))} is non-nullable." ) - .And.Message - .Should().Be(expectedMessage); + .And.Message.Should() + .Be(expectedMessage); } [Fact] diff --git a/tests/DbConnectionPlus.UnitTests/Mocks/MockDbParameterCollection.cs b/tests/DbConnectionPlus.UnitTests/Mocks/MockDbParameterCollection.cs index 6070e5f..8721897 100644 --- a/tests/DbConnectionPlus.UnitTests/Mocks/MockDbParameterCollection.cs +++ b/tests/DbConnectionPlus.UnitTests/Mocks/MockDbParameterCollection.cs @@ -31,8 +31,7 @@ public override int Add(object value) public override bool Contains(string value) => this.IndexOf(value) != -1; /// - public override void CopyTo(Array array, int index) => - this.parameters.CopyTo((DbParameter[])array, index); + public override void CopyTo(Array array, int index) => this.parameters.CopyTo((DbParameter[])array, index); /// public override IEnumerator GetEnumerator() => this.parameters.GetEnumerator(); @@ -55,8 +54,7 @@ public override int IndexOf(string parameterName) } /// - public override void Insert(int index, object value) => - this.parameters.Insert(index, (DbParameter)value); + public override void Insert(int index, object value) => this.parameters.Insert(index, (DbParameter)value); /// public override void Remove(object value) => this.parameters.Remove((DbParameter)value); @@ -65,8 +63,7 @@ public override void Insert(int index, object value) => public override void RemoveAt(int index) => this.parameters.RemoveAt(index); /// - public override void RemoveAt(string parameterName) => - this.RemoveAt(this.IndexOfChecked(parameterName)); + public override void RemoveAt(string parameterName) => this.RemoveAt(this.IndexOfChecked(parameterName)); /// protected override DbParameter GetParameter(int index) => this.parameters[index]; @@ -76,8 +73,7 @@ protected override DbParameter GetParameter(string parameterName) => this.GetParameter(this.IndexOfChecked(parameterName)); /// - protected override void SetParameter(int index, DbParameter value) => - this.parameters[index] = value; + protected override void SetParameter(int index, DbParameter value) => this.parameters[index] = value; /// protected override void SetParameter(string parameterName, DbParameter value) => diff --git a/tests/DbConnectionPlus.UnitTests/Readers/CommandDisposingDataReaderDecoratorTests.cs b/tests/DbConnectionPlus.UnitTests/Readers/CommandDisposingDataReaderDecoratorTests.cs index cc79dce..3c05f97 100644 --- a/tests/DbConnectionPlus.UnitTests/Readers/CommandDisposingDataReaderDecoratorTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Readers/CommandDisposingDataReaderDecoratorTests.cs @@ -52,8 +52,7 @@ public void GetFieldValue_ShouldForwardToDecoratedReader() this.decoratedReader.GetFieldValue(ordinal).Returns(returnValue); - this.decorator.GetFieldValue(ordinal) - .Should().Be(returnValue); + this.decorator.GetFieldValue(ordinal).Should().Be(returnValue); this.decoratedReader.Received().GetFieldValue(ordinal); } @@ -67,8 +66,7 @@ public async Task GetFieldValueAsync_ShouldForwardToDecoratedReader() this.decoratedReader.GetFieldValueAsync(ordinal, CancellationToken.None) .Returns(Task.FromResult(returnValue)); - (await this.decorator.GetFieldValueAsync(ordinal, CancellationToken.None)) - .Should().Be(returnValue); + (await this.decorator.GetFieldValueAsync(ordinal, CancellationToken.None)).Should().Be(returnValue); await this.decoratedReader.Received().GetFieldValueAsync(ordinal, CancellationToken.None); } @@ -82,19 +80,14 @@ public void ShouldForwardAllMethodCallsToDecoratedReader() nameof(CommandDisposingDataReaderDecorator.DisposeAsync), nameof(CommandDisposingDataReaderDecorator.GetData), nameof(CommandDisposingDataReaderDecorator.GetFieldValue), - nameof(CommandDisposingDataReaderDecorator.GetFieldValueAsync) + nameof(CommandDisposingDataReaderDecorator.GetFieldValueAsync), }; var fixture = new Fixture(); fixture.Customize(new AutoNSubstituteCustomization()); fixture.Register(() => new DataTable()); - DecoratorAssertions.AssertDecoratorForwardsAllCalls( - fixture, - this.decorator, - this.decoratedReader, - exceptions - ); + DecoratorAssertions.AssertDecoratorForwardsAllCalls(fixture, this.decorator, this.decoratedReader, exceptions); } [Fact] diff --git a/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderOptionsTests.cs b/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderOptionsTests.cs index 53e2f75..3d715fd 100644 --- a/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderOptionsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderOptionsTests.cs @@ -13,14 +13,9 @@ public void GetFieldType_CharPropertyReadAsString_ShouldReturnString() { Entity[] entities = [new()]; - using var reader = CreateReader( - typeof(Entity), - entities, - EnumerableReaderOptions.ReadCharsAsStrings - ); + using var reader = CreateReader(typeof(Entity), entities, EnumerableReaderOptions.ReadCharsAsStrings); - reader.GetFieldType(reader.GetOrdinal("CharValue")) - .Should().Be(typeof(string)); + reader.GetFieldType(reader.GetOrdinal("CharValue")).Should().Be(typeof(string)); } [Fact] @@ -36,8 +31,7 @@ public void GetFieldType_EnumValuesSerializedAsIntegers_ShouldReturnInt32() EnumerableReaderOptions.SerializeEnums ); - reader.GetFieldType(0) - .Should().Be(typeof(int)); + reader.GetFieldType(0).Should().Be(typeof(int)); } [Fact] @@ -53,8 +47,7 @@ public void GetFieldType_EnumValuesSerializedAsStrings_ShouldReturnString() EnumerableReaderOptions.SerializeEnums ); - reader.GetFieldType(0) - .Should().Be(typeof(string)); + reader.GetFieldType(0).Should().Be(typeof(string)); } [Fact] @@ -70,11 +63,9 @@ public void GetInt32_EnumValuesSerialized_ShouldReturnEnumAsInt32() foreach (var entity in entities) { - reader.Read() - .Should().BeTrue(); + reader.Read().Should().BeTrue(); - reader.GetInt32(0) - .Should().Be((int)entity.Enum); + reader.GetInt32(0).Should().Be((int)entity.Enum); } } @@ -83,16 +74,11 @@ public void GetString_CharPropertyReadAsString_ShouldConvertToString() { Entity[] entities = [new() { CharValue = Generate.Single() }]; - using var reader = CreateReader( - typeof(Entity), - entities, - EnumerableReaderOptions.ReadCharsAsStrings - ); + using var reader = CreateReader(typeof(Entity), entities, EnumerableReaderOptions.ReadCharsAsStrings); reader.Read(); - reader.GetString(reader.GetOrdinal("CharValue")) - .Should().Be(entities[0].CharValue.ToString()); + reader.GetString(reader.GetOrdinal("CharValue")).Should().Be(entities[0].CharValue.ToString()); } [Fact] @@ -108,11 +94,9 @@ public void GetString_EnumValuesSerialized_ShouldReturnEnumAsString() foreach (var entity in entities) { - reader.Read() - .Should().BeTrue(); + reader.Read().Should().BeTrue(); - reader.GetString(0) - .Should().Be(entity.Enum.ToString()); + reader.GetString(0).Should().Be(entity.Enum.ToString()); } } @@ -121,11 +105,7 @@ public void GetValues_CharPropertyReadAsString_ShouldConvertToString() { Entity[] entities = [new() { CharValue = Generate.Single() }]; - using var reader = CreateReader( - typeof(Entity), - entities, - EnumerableReaderOptions.ReadCharsAsStrings - ); + using var reader = CreateReader(typeof(Entity), entities, EnumerableReaderOptions.ReadCharsAsStrings); reader.Read(); @@ -133,8 +113,7 @@ public void GetValues_CharPropertyReadAsString_ShouldConvertToString() reader.GetValues(values); - values[reader.GetOrdinal("CharValue")] - .Should().Be(entities[0].CharValue.ToString()); + values[reader.GetOrdinal("CharValue")].Should().Be(entities[0].CharValue.ToString()); } [Fact] @@ -152,16 +131,13 @@ public void GetValues_EnumValuesSerializedAsIntegers_ShouldSerializeEnumsAsInteg foreach (var entity in entities) { - reader.Read() - .Should().BeTrue(); + reader.Read().Should().BeTrue(); var values = new object[reader.FieldCount]; - reader.GetValues(values) - .Should().Be(reader.FieldCount); + reader.GetValues(values).Should().Be(reader.FieldCount); - values[0] - .Should().Be((int)entity.Enum); + values[0].Should().Be((int)entity.Enum); } } @@ -180,27 +156,20 @@ public void GetValues_EnumValuesSerializedAsStrings_ShouldSerializeEnumsAsString foreach (var entity in entities) { - reader.Read() - .Should().BeTrue(); + reader.Read().Should().BeTrue(); var values = new object[reader.FieldCount]; - reader.GetValues(values) - .Should().Be(reader.FieldCount); + reader.GetValues(values).Should().Be(reader.FieldCount); - values[0] - .Should().Be(entity.Enum.ToString()); + values[0].Should().Be(entity.Enum.ToString()); } } [Fact] public void GetValues_NoOptions_ShouldReturnRawEnumAndCharValues() { - var entity = new Entity - { - EnumValue = Generate.Single(), - CharValue = Generate.Single() - }; + var entity = new Entity { EnumValue = Generate.Single(), CharValue = Generate.Single() }; using var reader = CreateReader(typeof(Entity), new[] { entity }, EnumerableReaderOptions.None); @@ -209,11 +178,9 @@ public void GetValues_NoOptions_ShouldReturnRawEnumAndCharValues() var values = new object[reader.FieldCount]; reader.GetValues(values); - values[reader.GetOrdinal("EnumValue")] - .Should().Be(entity.EnumValue); + values[reader.GetOrdinal("EnumValue")].Should().Be(entity.EnumValue); - values[reader.GetOrdinal("CharValue")] - .Should().Be(entity.CharValue); + values[reader.GetOrdinal("CharValue")].Should().Be(entity.CharValue); } [Fact] @@ -227,11 +194,9 @@ public void GetValue_NullProperty_ShouldReturnDbNull() var ordinal = reader.GetOrdinal("StringValue"); - reader.GetValue(ordinal) - .Should().Be(DBNull.Value); + reader.GetValue(ordinal).Should().Be(DBNull.Value); - reader.IsDBNull(ordinal) - .Should().BeTrue(); + reader.IsDBNull(ordinal).Should().BeTrue(); } /// @@ -241,7 +206,11 @@ public void GetValue_NullProperty_ShouldReturnDbNull() /// The entities the reader reads. /// The behaviours the reader applies. /// The created reader. - private static EnumerableReader CreateReader(Type entityType, IEnumerable entities, EnumerableReaderOptions options) => + private static EnumerableReader CreateReader( + Type entityType, + IEnumerable entities, + EnumerableReaderOptions options + ) => new( entities, [.. EntityHelper.GetEntityTypeMetadata(entityType).MappedProperties.Where(a => a.CanRead)], diff --git a/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderTests.cs b/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderTests.cs index fcd1685..8532ef2 100644 --- a/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderTests.cs @@ -19,13 +19,11 @@ public EnumerableReaderTests() [Fact] public void Close_ShouldCloseReader() { - this.enumerableReader.IsClosed - .Should().BeFalse(); + this.enumerableReader.IsClosed.Should().BeFalse(); this.enumerableReader.Close(); - this.enumerableReader.IsClosed - .Should().BeTrue(); + this.enumerableReader.IsClosed.Should().BeTrue(); } [Fact] @@ -62,16 +60,14 @@ public async Task CloseAsync_ShouldDisposeEnumerator() public void Constructor_FieldNameEmptyOrWhitespace_ShouldThrow() { Invoking(() => new EnumerableReader(this.testValues, typeof(int), string.Empty)) - .Should().Throw(); + .Should() + .Throw(); - Invoking(() => new EnumerableReader(this.testValues, typeof(int), " ")) - .Should().Throw(); + Invoking(() => new EnumerableReader(this.testValues, typeof(int), " ")).Should().Throw(); } [Fact] - public void Depth_ShouldAlwaysReturnZero() => - this.enumerableReader.Depth - .Should().Be(0); + public void Depth_ShouldAlwaysReturnZero() => this.enumerableReader.Depth.Should().Be(0); [Fact] public void Dispose_ShouldDisposeEnumerator() @@ -104,56 +100,54 @@ public async Task DisposeAsync_ShouldDisposeEnumerator() } [Fact] - public void FieldCount_ShouldAlwaysReturnOne() => - this.enumerableReader.FieldCount - .Should().Be(1); + public void FieldCount_ShouldAlwaysReturnOne() => this.enumerableReader.FieldCount.Should().Be(1); [Fact] public void GetDataTypeName_InvalidOrdinal_ShouldThrow() => Invoking(() => this.enumerableReader.GetDataTypeName(1)) - .Should().Throw() + .Should() + .Throw() .WithMessage("The specified ordinal 1 is not supported. The only supported ordinal is zero.*"); [Fact] public void GetDataTypeName_ValidOrdinal_ShouldReturnNameOfValuesTypePassedToConstructor() => - this.enumerableReader.GetDataTypeName(0) - .Should().Be(nameof(Int32)); + this.enumerableReader.GetDataTypeName(0).Should().Be(nameof(Int32)); [Fact] public void GetFieldType_InvalidOrdinal_ShouldThrow() => Invoking(() => this.enumerableReader.GetFieldType(1)) - .Should().Throw() + .Should() + .Throw() .WithMessage("The specified ordinal 1 is not supported. The only supported ordinal is zero.*"); [Fact] public void GetFieldType_ValidOrdinal_ShouldReturnValuesTypePassedToConstructor() => - this.enumerableReader.GetFieldType(0) - .Should().Be(typeof(int)); + this.enumerableReader.GetFieldType(0).Should().Be(typeof(int)); [Fact] public void GetName_InvalidOrdinal_ShouldThrow() => Invoking(() => this.enumerableReader.GetName(1)) - .Should().Throw() + .Should() + .Throw() .WithMessage("The specified ordinal 1 is not supported. The only supported ordinal is zero.*"); [Fact] public void GetName_ValidOrdinal_ShouldReturnFieldNamePassedToConstructor() => - this.enumerableReader.GetName(0) - .Should().Be(FieldName); + this.enumerableReader.GetName(0).Should().Be(FieldName); [Fact] public void GetOrdinal_InvalidFieldName_ShouldThrow() => Invoking(() => this.enumerableReader.GetOrdinal("nonExistentField")) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The specified field name 'nonExistentField' is not supported. The only supported field name is " + - "'Value'.*" + "The specified field name 'nonExistentField' is not supported. The only supported field name is " + + "'Value'.*" ); [Fact] public void GetOrdinal_ValidFieldName_ShouldReturnOrdinal() => - this.enumerableReader.GetOrdinal(FieldName) - .Should().Be(0); + this.enumerableReader.GetOrdinal(FieldName).Should().Be(0); [Fact] public void GetTypedValue_SingleColumn_ShouldReturnCurrentValue() @@ -178,7 +172,8 @@ public void GetValue_InvalidOrdinal_ShouldThrow() this.enumerableReader.Read(); Invoking(() => this.enumerableReader.GetValue(1)) - .Should().Throw() + .Should() + .Throw() .WithMessage("The specified ordinal 1 is not supported. The only supported ordinal is zero.*"); } @@ -189,8 +184,7 @@ public void GetValue_ValidOrdinal_ShouldReturnCurrentValue() { this.enumerableReader.Read(); - this.enumerableReader.GetValue(0) - .Should().Be(value); + this.enumerableReader.GetValue(0).Should().Be(value); } } @@ -200,7 +194,8 @@ public void GetValues_BufferTooSmall_ShouldThrow() this.enumerableReader.Read(); Invoking(() => this.enumerableReader.GetValues([])) - .Should().Throw() + .Should() + .Throw() .WithMessage("The specified array must have a length greater than or equal to 1.*"); } @@ -213,8 +208,7 @@ public void GetValues_ShouldAlwaysReturnOne() { this.enumerableReader.Read(); - this.enumerableReader.GetValues(values) - .Should().Be(1); + this.enumerableReader.GetValues(values).Should().Be(1); } } @@ -229,37 +223,43 @@ public void GetValues_ShouldFillBufferWithValue() this.enumerableReader.GetValues(buffer); - buffer[0] - .Should().Be(value); + buffer[0].Should().Be(value); } } [Fact] public void Fields_MultiColumn_ShouldMatchMappedReadableProperties() { - var properties = EntityHelper.GetEntityTypeMetadata(typeof(Entity)).MappedProperties.Where(a => a.CanRead) + var properties = EntityHelper + .GetEntityTypeMetadata(typeof(Entity)) + .MappedProperties.Where(a => a.CanRead) .ToArray(); using var reader = new EnumerableReader(new Entity[] { new() }, properties, EnumerableReaderOptions.None); - reader.FieldCount - .Should().Be(properties.Length); + reader.FieldCount.Should().Be(properties.Length); - Enumerable.Range(0, properties.Length).Select(reader.GetName) - .Should().Equal(properties.Select(a => a.PropertyName)); + Enumerable + .Range(0, properties.Length) + .Select(reader.GetName) + .Should() + .Equal(properties.Select(a => a.PropertyName)); - properties.Select(a => reader.GetOrdinal(a.PropertyName)) - .Should().Equal(Enumerable.Range(0, properties.Length)); + properties + .Select(a => reader.GetOrdinal(a.PropertyName)) + .Should() + .Equal(Enumerable.Range(0, properties.Length)); - reader.GetOrdinal("NonExistentField") - .Should().Be(-1); + reader.GetOrdinal("NonExistentField").Should().Be(-1); } [Fact] public void GetValues_MultiColumnShortBuffer_ShouldFillAvailableEntries() { var entity = Generate.Single(); - var properties = EntityHelper.GetEntityTypeMetadata(typeof(Entity)).MappedProperties.Where(a => a.CanRead) + var properties = EntityHelper + .GetEntityTypeMetadata(typeof(Entity)) + .MappedProperties.Where(a => a.CanRead) .ToArray(); using var reader = new EnumerableReader(new[] { entity }, properties, EnumerableReaderOptions.None); @@ -268,16 +268,13 @@ public void GetValues_MultiColumnShortBuffer_ShouldFillAvailableEntries() var values = new object[2]; - reader.GetValues(values) - .Should().Be(values.Length); + reader.GetValues(values).Should().Be(values.Length); values.Should().Equal(properties.Take(values.Length).Select(a => a.PropertyGetter!(entity) ?? DBNull.Value)); } [Fact] - public void HasRows_ShouldAlwaysReturnTrue() => - this.enumerableReader.HasRows - .Should().BeTrue(); + public void HasRows_ShouldAlwaysReturnTrue() => this.enumerableReader.HasRows.Should().BeTrue(); [Fact] public void Indexer_InvalidFieldName_ShouldThrow() @@ -285,10 +282,11 @@ public void Indexer_InvalidFieldName_ShouldThrow() this.enumerableReader.Read(); Invoking(() => this.enumerableReader["NonExistentField"]) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The specified field name 'NonExistentField' is not supported. The only supported field name is " + - "'Value'.*" + "The specified field name 'NonExistentField' is not supported. The only supported field name is " + + "'Value'.*" ); } @@ -298,7 +296,8 @@ public void Indexer_InvalidOrdinal_ShouldThrow() this.enumerableReader.Read(); Invoking(() => this.enumerableReader[1]) - .Should().Throw() + .Should() + .Throw() .WithMessage("The specified ordinal 1 is not supported. The only supported ordinal is zero.*"); } @@ -309,8 +308,7 @@ public void Indexer_ValidName_ShouldReturnCurrentValue() { this.enumerableReader.Read(); - this.enumerableReader[FieldName] - .Should().Be(value); + this.enumerableReader[FieldName].Should().Be(value); } } @@ -321,27 +319,25 @@ public void Indexer_ValidOrdinal_ShouldReturnCurrentValue() { this.enumerableReader.Read(); - this.enumerableReader[0] - .Should().Be(value); + this.enumerableReader[0].Should().Be(value); } } [Fact] public void IsClosed_ShouldReturnWhetherReaderIsClosed() { - this.enumerableReader.IsClosed - .Should().BeFalse(); + this.enumerableReader.IsClosed.Should().BeFalse(); this.enumerableReader.Close(); - this.enumerableReader.IsClosed - .Should().BeTrue(); + this.enumerableReader.IsClosed.Should().BeTrue(); } [Fact] public void IsDBNull_InvalidOrdinal_ShouldThrow() => Invoking(() => this.enumerableReader.IsDBNull(1)) - .Should().Throw() + .Should() + .Throw() .WithMessage("The specified ordinal 1 is not supported. The only supported ordinal is zero.*"); [Fact] @@ -354,15 +350,12 @@ public void IsDBNull_ValidOrdinal_ShouldReturnWhetherCurrentValueIsNull() { readerWithNulls.Read(); - readerWithNulls.IsDBNull(0) - .Should().Be(value is null); + readerWithNulls.IsDBNull(0).Should().Be(value is null); } } [Fact] - public void NextResult_ShouldAlwaysReturnFalse() => - this.enumerableReader.NextResult() - .Should().BeFalse(); + public void NextResult_ShouldAlwaysReturnFalse() => this.enumerableReader.NextResult().Should().BeFalse(); [Fact] public void Read_ReaderIsClosed_ShouldThrow() @@ -370,7 +363,8 @@ public void Read_ReaderIsClosed_ShouldThrow() this.enumerableReader.Close(); Invoking(() => this.enumerableReader.Read()) - .Should().Throw() + .Should() + .Throw() .WithMessage("Invalid attempt to call Read when reader is closed.*"); } @@ -379,18 +373,14 @@ public void Read_ShouldReturnTrueUntilAllValuesAreRead() { foreach (var _ in this.testValues) { - this.enumerableReader.Read() - .Should().BeTrue(); + this.enumerableReader.Read().Should().BeTrue(); } - this.enumerableReader.Read() - .Should().BeFalse(); + this.enumerableReader.Read().Should().BeFalse(); } [Fact] - public void RecordsAffected_ShouldAlwaysReturnMinusOne() => - this.enumerableReader.RecordsAffected - .Should().Be(-1); + public void RecordsAffected_ShouldAlwaysReturnMinusOne() => this.enumerableReader.RecordsAffected.Should().Be(-1); [Fact] public void ShouldGuardAgainstNullArguments() => @@ -399,8 +389,9 @@ public void ShouldGuardAgainstNullArguments() => private static void AssertSingleColumnAccessor( object value, [DynamicallyAccessedMembers( - DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] - Type valuesType, + DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties + )] + Type valuesType, Func accessor ) { @@ -408,8 +399,7 @@ Func accessor reader.Read(); - accessor(reader) - .Should().Be(value); + accessor(reader).Should().Be(value); } private readonly EnumerableReader enumerableReader; diff --git a/tests/DbConnectionPlus.UnitTests/SqlStatements/InterpolatedSqlStatementTests.cs b/tests/DbConnectionPlus.UnitTests/SqlStatements/InterpolatedSqlStatementTests.cs index c2a005e..912d5ce 100644 --- a/tests/DbConnectionPlus.UnitTests/SqlStatements/InterpolatedSqlStatementTests.cs +++ b/tests/DbConnectionPlus.UnitTests/SqlStatements/InterpolatedSqlStatementTests.cs @@ -11,14 +11,11 @@ public void AppendFormatted_InterpolatedParameter_ShouldStoreParameter() InterpolatedSqlStatement statement = $"SELECT {Parameter(value1)}"; - statement.Fragments - .Should().HaveCount(2); + statement.Fragments.Should().HaveCount(2); - statement.Fragments[0] - .Should().Be(new Literal("SELECT ")); + statement.Fragments[0].Should().Be(new Literal("SELECT ")); - statement.Fragments[1] - .Should().Be(new InterpolatedParameter("Value1", value1)); + statement.Fragments[1].Should().Be(new InterpolatedParameter("Value1", value1)); } [Fact] @@ -27,30 +24,24 @@ public void AppendFormatted_InterpolatedParameter_ShouldSupportComplexExpression const double baseDiscount = 0.1; var entityIds = Generate.Ids(20); - InterpolatedSqlStatement statement = - $""" - SELECT {Parameter(baseDiscount * 5 / 3)}, - {Parameter(entityIds.Where(a => a > 5).ToArray()[0])} - """; + InterpolatedSqlStatement statement = $""" + SELECT {Parameter(baseDiscount * 5 / 3)}, + {Parameter(entityIds.Where(a => a > 5).ToArray()[0])} + """; - statement.Fragments - .Should().HaveCount(4); + statement.Fragments.Should().HaveCount(4); - statement.Fragments[0] - .Should().Be(new Literal("SELECT ")); + statement.Fragments[0].Should().Be(new Literal("SELECT ")); - statement.Fragments[1] - .Should().Be(new InterpolatedParameter("BaseDiscount53", baseDiscount * 5 / 3)); + statement.Fragments[1].Should().Be(new InterpolatedParameter("BaseDiscount53", baseDiscount * 5 / 3)); - statement.Fragments[2] - .Should().Be(new Literal($",{Environment.NewLine} ")); + statement.Fragments[2].Should().Be(new Literal($",{Environment.NewLine} ")); - statement.Fragments[3] - .Should().BeEquivalentTo( - new InterpolatedParameter( - "EntityIdsWhereaa5ToArray0", - entityIds.Where(a => a > 5).ToArray()[0] - ) + statement + .Fragments[3] + .Should() + .BeEquivalentTo( + new InterpolatedParameter("EntityIdsWhereaa5ToArray0", entityIds.Where(a => a > 5).ToArray()[0]) ); } @@ -60,55 +51,47 @@ public void AppendFormatted_InterpolatedTemporaryTables_ShouldStoreTemporaryTabl var entities = Generate.Multiple(); var entityIds = Generate.Ids(); - InterpolatedSqlStatement statement = - $""" - SELECT Value FROM {TemporaryTable(entityIds)} - UNION - SELECT Id FROM {TemporaryTable(entities)} - """; + InterpolatedSqlStatement statement = $""" + SELECT Value FROM {TemporaryTable(entityIds)} + UNION + SELECT Id FROM {TemporaryTable(entities)} + """; - statement.TemporaryTables - .Should().HaveCount(2); + statement.TemporaryTables.Should().HaveCount(2); var table1 = statement.TemporaryTables[0]; - table1.Name - .Should().StartWith("EntityIds_"); + table1.Name.Should().StartWith("EntityIds_"); - table1.Values - .Should().BeEquivalentTo(entityIds); + table1.Values.Should().BeEquivalentTo(entityIds); - table1.ValuesType - .Should().Be(typeof(long)); + table1.ValuesType.Should().Be(typeof(long)); - statement.Fragments[2] - .Should().Be(new Literal($"{Environment.NewLine}UNION{Environment.NewLine}SELECT Id FROM ")); + statement + .Fragments[2] + .Should() + .Be(new Literal($"{Environment.NewLine}UNION{Environment.NewLine}SELECT Id FROM ")); var table2 = statement.TemporaryTables[1]; - table2.Name - .Should().StartWith("Entities_"); + table2.Name.Should().StartWith("Entities_"); - table2.Values - .Should().BeEquivalentTo(entities); + table2.Values.Should().BeEquivalentTo(entities); - table2.ValuesType - .Should().Be(typeof(Entity)); + table2.ValuesType.Should().Be(typeof(Entity)); - statement.Fragments - .Should().HaveCount(4); + statement.Fragments.Should().HaveCount(4); - statement.Fragments[0] - .Should().Be(new Literal("SELECT Value FROM ")); + statement.Fragments[0].Should().Be(new Literal("SELECT Value FROM ")); - statement.Fragments[1] - .Should().Be(table1); + statement.Fragments[1].Should().Be(table1); - statement.Fragments[2] - .Should().Be(new Literal($"{Environment.NewLine}UNION{Environment.NewLine}SELECT Id FROM ")); + statement + .Fragments[2] + .Should() + .Be(new Literal($"{Environment.NewLine}UNION{Environment.NewLine}SELECT Id FROM ")); - statement.Fragments[3] - .Should().Be(table2); + statement.Fragments[3].Should().Be(table2); } [Fact] @@ -120,47 +103,35 @@ public void AppendFormatted_MultipleInterpolatedParameters_ShouldStoreParameters InterpolatedSqlStatement statement = $"SELECT {Parameter(value1)}, {Parameter(value2)}, {Parameter(value3)}"; - statement.Fragments - .Should().HaveCount(6); + statement.Fragments.Should().HaveCount(6); - statement.Fragments[0] - .Should().Be(new Literal("SELECT ")); + statement.Fragments[0].Should().Be(new Literal("SELECT ")); - statement.Fragments[1] - .Should().Be(new InterpolatedParameter("Value1", value1)); + statement.Fragments[1].Should().Be(new InterpolatedParameter("Value1", value1)); - statement.Fragments[2] - .Should().Be(new Literal(", ")); + statement.Fragments[2].Should().Be(new Literal(", ")); - statement.Fragments[3] - .Should().Be(new InterpolatedParameter("Value2", value2)); + statement.Fragments[3].Should().Be(new InterpolatedParameter("Value2", value2)); - statement.Fragments[4] - .Should().Be(new Literal(", ")); + statement.Fragments[4].Should().Be(new Literal(", ")); - statement.Fragments[5] - .Should().Be(new InterpolatedParameter("Value3", value3)); + statement.Fragments[5].Should().Be(new InterpolatedParameter("Value3", value3)); } [Fact] public void AppendFormatted_ShouldFormatAndStoreLiteral() { - InterpolatedSqlStatement statement = $"SELECT {123.45,10:N2}, {123.45,-10:N2}"; + InterpolatedSqlStatement statement = $"SELECT {123.45, 10:N2}, {123.45, -10:N2}"; - statement.Fragments - .Should().HaveCount(4); + statement.Fragments.Should().HaveCount(4); - statement.Fragments[0] - .Should().Be(new Literal("SELECT ")); + statement.Fragments[0].Should().Be(new Literal("SELECT ")); - statement.Fragments[1] - .Should().Be(new Literal(" 123.45")); + statement.Fragments[1].Should().Be(new Literal(" 123.45")); - statement.Fragments[2] - .Should().Be(new Literal(", ")); + statement.Fragments[2].Should().Be(new Literal(", ")); - statement.Fragments[3] - .Should().Be(new Literal("123.45 ")); + statement.Fragments[3].Should().Be(new Literal("123.45 ")); } [Fact] @@ -170,17 +141,16 @@ public void AppendLiteral_ShouldStoreLiteral() InterpolatedSqlStatement statement = $"SELECT 1"; #pragma warning restore RCS1214 // Unnecessary interpolated string - statement.Fragments - .Should().HaveCount(1); + statement.Fragments.Should().HaveCount(1); - statement.Fragments[0] - .Should().Be(new Literal("SELECT 1")); + statement.Fragments[0].Should().Be(new Literal("SELECT 1")); } [Fact] public void Constructor_Code_Parameters_DuplicateParameterName_ShouldThrow() { - Invoking(() => new InterpolatedSqlStatement( + Invoking(() => + new InterpolatedSqlStatement( "Code", new("Parameter1", "Value1"), new("Parameter1", "Value2"), @@ -188,14 +158,16 @@ public void Constructor_Code_Parameters_DuplicateParameterName_ShouldThrow() new("Parameter2", "Value4") ) ) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The specified parameters have the following duplicate parameter names: " + - "'Parameter1', 'Parameter1', 'Parameter2', 'Parameter2'. Make sure each parameter name is only used " + - "once.*" + "The specified parameters have the following duplicate parameter names: " + + "'Parameter1', 'Parameter1', 'Parameter2', 'Parameter2'. Make sure each parameter name is only used " + + "once.*" ); - Invoking(() => new InterpolatedSqlStatement( + Invoking(() => + new InterpolatedSqlStatement( "Code", new("Parameter1", "Value1"), new("PARAMETER1", "Value2"), @@ -203,11 +175,12 @@ public void Constructor_Code_Parameters_DuplicateParameterName_ShouldThrow() new("PARAMETER2", "Value4") ) ) - .Should().Throw() + .Should() + .Throw() .WithMessage( - "The specified parameters have the following duplicate parameter names: " + - "'Parameter1', 'PARAMETER1', 'Parameter2', 'PARAMETER2'. Make sure each parameter name is only used " + - "once.*" + "The specified parameters have the following duplicate parameter names: " + + "'Parameter1', 'PARAMETER1', 'Parameter2', 'PARAMETER2'. Make sure each parameter name is only used " + + "once.*" ); } @@ -216,11 +189,9 @@ public void Constructor_Code_Parameters_ShouldStoreCodeAsLiteral() { var statement = new InterpolatedSqlStatement("SELECT 1"); - statement.Fragments - .Should().HaveCount(1); + statement.Fragments.Should().HaveCount(1); - statement.Fragments[0] - .Should().Be(new Literal("SELECT 1")); + statement.Fragments[0].Should().Be(new Literal("SELECT 1")); } [Fact] @@ -237,20 +208,15 @@ public void Constructor_Code_Parameters_ShouldStoreParameters() ("Parameter3", value3) ); - statement.Fragments - .Should().HaveCount(4); + statement.Fragments.Should().HaveCount(4); - statement.Fragments[0] - .Should().Be(new Literal("SELECT @Parameter1, @Parameter2, @Parameter3")); + statement.Fragments[0].Should().Be(new Literal("SELECT @Parameter1, @Parameter2, @Parameter3")); - statement.Fragments[1] - .Should().Be(new Parameter("Parameter1", value1)); + statement.Fragments[1].Should().Be(new Parameter("Parameter1", value1)); - statement.Fragments[2] - .Should().Be(new Parameter("Parameter2", value2)); + statement.Fragments[2].Should().Be(new Parameter("Parameter2", value2)); - statement.Fragments[3] - .Should().Be(new Parameter("Parameter3", value3)); + statement.Fragments[3].Should().Be(new Parameter("Parameter3", value3)); } [Fact] @@ -258,8 +224,7 @@ public void Constructor_LiteralLength_FormattedCount_ShouldInitializeInstance() { var statement = new InterpolatedSqlStatement(100, 10); - statement.Fragments - .Should().BeEmpty(); + statement.Fragments.Should().BeEmpty(); } [Fact] @@ -271,69 +236,57 @@ public void Fragments_ShouldGetFragments() var entityIds = Generate.Ids(); var entities = Generate.Multiple(); - InterpolatedSqlStatement statement = - $""" - SELECT {Parameter(value1)} - UNION - SELECT {Parameter(value2)} - UNION - SELECT {Parameter(value3)} - UNION - SELECT Value FROM {TemporaryTable(entityIds)} - UNION - SELECT Id FROM {TemporaryTable(entities)} - """; + InterpolatedSqlStatement statement = $""" + SELECT {Parameter(value1)} + UNION + SELECT {Parameter(value2)} + UNION + SELECT {Parameter(value3)} + UNION + SELECT Value FROM {TemporaryTable(entityIds)} + UNION + SELECT Id FROM {TemporaryTable(entities)} + """; - statement.Fragments - .Should().HaveCount(10); + statement.Fragments.Should().HaveCount(10); - statement.Fragments[0] - .Should().Be(new Literal("SELECT ")); + statement.Fragments[0].Should().Be(new Literal("SELECT ")); - statement.Fragments[1] - .Should().Be(new InterpolatedParameter("Value1", value1)); + statement.Fragments[1].Should().Be(new InterpolatedParameter("Value1", value1)); - statement.Fragments[2] - .Should().Be(new Literal($"{Environment.NewLine}UNION{Environment.NewLine}SELECT ")); + statement.Fragments[2].Should().Be(new Literal($"{Environment.NewLine}UNION{Environment.NewLine}SELECT ")); - statement.Fragments[3] - .Should().Be(new InterpolatedParameter("Value2", value2)); + statement.Fragments[3].Should().Be(new InterpolatedParameter("Value2", value2)); - statement.Fragments[4] - .Should().Be(new Literal($"{Environment.NewLine}UNION{Environment.NewLine}SELECT ")); + statement.Fragments[4].Should().Be(new Literal($"{Environment.NewLine}UNION{Environment.NewLine}SELECT ")); - statement.Fragments[5] - .Should().Be(new InterpolatedParameter("Value3", value3)); + statement.Fragments[5].Should().Be(new InterpolatedParameter("Value3", value3)); - statement.Fragments[6] - .Should().Be(new Literal($"{Environment.NewLine}UNION{Environment.NewLine}SELECT Value FROM ")); + statement + .Fragments[6] + .Should() + .Be(new Literal($"{Environment.NewLine}UNION{Environment.NewLine}SELECT Value FROM ")); - var table1 = statement.Fragments[7] - .Should().BeOfType().Subject; + var table1 = statement.Fragments[7].Should().BeOfType().Subject; - table1.Name - .Should().StartWith("EntityIds_"); + table1.Name.Should().StartWith("EntityIds_"); - table1.Values - .Should().BeEquivalentTo(entityIds); + table1.Values.Should().BeEquivalentTo(entityIds); - table1.ValuesType - .Should().Be(typeof(long)); + table1.ValuesType.Should().Be(typeof(long)); - statement.Fragments[8] - .Should().Be(new Literal($"{Environment.NewLine}UNION{Environment.NewLine}SELECT Id FROM ")); + statement + .Fragments[8] + .Should() + .Be(new Literal($"{Environment.NewLine}UNION{Environment.NewLine}SELECT Id FROM ")); - var table2 = statement.Fragments[9] - .Should().BeOfType().Subject; + var table2 = statement.Fragments[9].Should().BeOfType().Subject; - table2.Name - .Should().StartWith("Entities_"); + table2.Name.Should().StartWith("Entities_"); - table2.Values - .Should().BeEquivalentTo(entities); + table2.Values.Should().BeEquivalentTo(entities); - table2.ValuesType - .Should().Be(typeof(Entity)); + table2.ValuesType.Should().Be(typeof(Entity)); } [Fact] @@ -341,11 +294,9 @@ public void FromString_EmptyString_ShouldCreateEmptyStatement() { var statement = InterpolatedSqlStatement.FromString(string.Empty); - statement.Fragments - .Should().HaveCount(1); + statement.Fragments.Should().HaveCount(1); - statement.Fragments[0] - .Should().Be(new Literal(string.Empty)); + statement.Fragments[0].Should().Be(new Literal(string.Empty)); } [Fact] @@ -353,36 +304,32 @@ public void FromString_ShouldCreateSqlStatementFromString() { var statement = InterpolatedSqlStatement.FromString("SELECT 1"); - statement.Fragments - .Should().HaveCount(1); + statement.Fragments.Should().HaveCount(1); - statement.Fragments[0] - .Should().Be(new Literal("SELECT 1")); + statement.Fragments[0].Should().Be(new Literal("SELECT 1")); } [Fact] public void ImplicitConversion_NullValue_ShouldThrow() => Invoking(() => - { - const string? sql = null; + { + const string? sql = null; #pragma warning disable RCS1124 // Inline local variable - InterpolatedSqlStatement statement = sql!; + InterpolatedSqlStatement statement = sql!; #pragma warning restore RCS1124 // Inline local variable - return statement; - } - ) - .Should().Throw(); + return statement; + }) + .Should() + .Throw(); [Fact] public void ImplicitConversion_ShouldCreateSqlStatementFromString() { InterpolatedSqlStatement statement = "SELECT 1"; - statement.Fragments - .Should().HaveCount(1); + statement.Fragments.Should().HaveCount(1); - statement.Fragments[0] - .Should().Be(new Literal("SELECT 1")); + statement.Fragments[0].Should().Be(new Literal("SELECT 1")); } [Fact] @@ -400,27 +347,21 @@ public void TemporaryTables_ShouldGetInterpolatedTemporaryTables() var entities = Generate.Multiple(); var entityIds = Generate.Ids(); - InterpolatedSqlStatement statement = - $""" - SELECT Value FROM {TemporaryTable(entityIds)} - UNION - SELECT Id FROM {TemporaryTable(entities)} - """; + InterpolatedSqlStatement statement = $""" + SELECT Value FROM {TemporaryTable(entityIds)} + UNION + SELECT Id FROM {TemporaryTable(entities)} + """; - statement.TemporaryTables - .Should().HaveCount(2); + statement.TemporaryTables.Should().HaveCount(2); - var table1 = statement.TemporaryTables[0] - .Should().BeOfType().Subject; + var table1 = statement.TemporaryTables[0].Should().BeOfType().Subject; - table1.Name - .Should().StartWith("EntityIds_"); + table1.Name.Should().StartWith("EntityIds_"); - table1.Values - .Should().BeEquivalentTo(entityIds); + table1.Values.Should().BeEquivalentTo(entityIds); - table1.ValuesType - .Should().Be(typeof(long)); + table1.ValuesType.Should().Be(typeof(long)); } [Fact] @@ -430,7 +371,7 @@ public void ToString_ShouldReturnStringRepresentationOfStatement() { new(1, "A", TestEnum.Value1), new(2, "B", TestEnum.Value2), - new(3, "C", TestEnum.Value3) + new(3, "C", TestEnum.Value3), }; List ids = [1, 2, 3]; @@ -439,84 +380,79 @@ public void ToString_ShouldReturnStringRepresentationOfStatement() const TestEnum enumValue = TestEnum.Value2; InterpolatedSqlStatement statement = $""" - SELECT * - FROM {TemporaryTable(items)} TItem - WHERE TItem.Id IN ( - SELECT Value - FROM {TemporaryTable(ids)} - ) - AND - TItem.Name = {Parameter(name)} - AND - TItem.Enum = {Parameter(enumValue)} - """; + SELECT * + FROM {TemporaryTable(items)} TItem + WHERE TItem.Id IN ( + SELECT Value + FROM {TemporaryTable(ids)} + ) + AND + TItem.Name = {Parameter(name)} + AND + TItem.Enum = {Parameter(enumValue)} + """; var temporaryTables = statement.TemporaryTables; - temporaryTables - .Should().HaveCount(2); + temporaryTables.Should().HaveCount(2); var itemsTable = temporaryTables[0]; - itemsTable.Name - .Should().StartWith("Items_"); + itemsTable.Name.Should().StartWith("Items_"); - itemsTable.Values - .Should().Be(items); + itemsTable.Values.Should().Be(items); - itemsTable.ValuesType - .Should().Be(typeof(Item)); + itemsTable.ValuesType.Should().Be(typeof(Item)); var idsTable = temporaryTables[1]; - idsTable.Name - .Should().StartWith("Ids_"); + idsTable.Name.Should().StartWith("Ids_"); - idsTable.Values - .Should().Be(ids); + idsTable.Values.Should().Be(ids); - idsTable.ValuesType - .Should().Be(typeof(int)); + idsTable.ValuesType.Should().Be(typeof(int)); - statement.ToString() - .Should().Be( + statement + .ToString() + .Should() + .Be( $$""" - SQL Statement - - Statement Code - -------------- - SELECT * - FROM {{itemsTable.Name}} TItem - WHERE TItem.Id IN ( - SELECT Value - FROM {{idsTable.Name}} - ) - AND - TItem.Name = @Name - AND - TItem.Enum = @EnumValue - -------------- - - Statement Parameters - -------------------- - Name = 'B' (System.String) - EnumValue = 'Value2' (RentADeveloper.DbConnectionPlus.UnitTests.TestData.TestEnum) - - Statement Temporary Tables - -------------------------- - - {{itemsTable.Name}} - -------------------------------------- - 'Item { Id = 1, Name = A, Enum = Value1 }' (RentADeveloper.DbConnectionPlus.UnitTests.TestData.Item) - 'Item { Id = 2, Name = B, Enum = Value2 }' (RentADeveloper.DbConnectionPlus.UnitTests.TestData.Item) - 'Item { Id = 3, Name = C, Enum = Value3 }' (RentADeveloper.DbConnectionPlus.UnitTests.TestData.Item) - - {{idsTable.Name}} - ------------------------------------ - '1' (System.Int32) - '2' (System.Int32) - '3' (System.Int32) - - """ + SQL Statement + + Statement Code + -------------- + SELECT * + FROM {{itemsTable.Name}} TItem + WHERE TItem.Id IN ( + SELECT Value + FROM {{idsTable.Name}} + ) + AND + TItem.Name = @Name + AND + TItem.Enum = @EnumValue + -------------- + + Statement Parameters + -------------------- + Name = 'B' (System.String) + EnumValue = 'Value2' (RentADeveloper.DbConnectionPlus.UnitTests.TestData.TestEnum) + + Statement Temporary Tables + -------------------------- + + {{itemsTable.Name}} + -------------------------------------- + 'Item { Id = 1, Name = A, Enum = Value1 }' (RentADeveloper.DbConnectionPlus.UnitTests.TestData.Item) + 'Item { Id = 2, Name = B, Enum = Value2 }' (RentADeveloper.DbConnectionPlus.UnitTests.TestData.Item) + 'Item { Id = 3, Name = C, Enum = Value3 }' (RentADeveloper.DbConnectionPlus.UnitTests.TestData.Item) + + {{idsTable.Name}} + ------------------------------------ + '1' (System.Int32) + '2' (System.Int32) + '3' (System.Int32) + + """ ); } } diff --git a/tests/DbConnectionPlus.UnitTests/StatementMethodTestsBase.cs b/tests/DbConnectionPlus.UnitTests/StatementMethodTestsBase.cs index 491def1..19664db 100644 --- a/tests/DbConnectionPlus.UnitTests/StatementMethodTestsBase.cs +++ b/tests/DbConnectionPlus.UnitTests/StatementMethodTestsBase.cs @@ -10,11 +10,24 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; /// The asynchronous version of the statement method to test. /// The synchronous version of the statement method to test. public abstract class StatementMethodTestsBase( - Func - asyncTestMethod, - Action - syncTestMethod - ) : UnitTestsBase + Func< + DbConnection, + InterpolatedSqlStatement, + DbTransaction?, + TimeSpan?, + CommandType, + CancellationToken, + Task + > asyncTestMethod, + Action< + DbConnection, + InterpolatedSqlStatement, + DbTransaction?, + TimeSpan?, + CommandType, + CancellationToken + > syncTestMethod +) : UnitTestsBase { [Fact] public async Task AsyncMethod_ShouldUseCommandTimeout() @@ -30,10 +43,11 @@ await this.asyncTestMethod( TestContext.Current.CancellationToken ); - this.MockInterceptDbCommand.Received().Invoke( - Arg.Is(cmd => cmd.CommandTimeout == (int)timeout.TotalSeconds), - Arg.Any>() - ); + this.MockInterceptDbCommand.Received() + .Invoke( + Arg.Is(cmd => cmd.CommandTimeout == (int)timeout.TotalSeconds), + Arg.Any>() + ); } [Fact] @@ -48,10 +62,11 @@ await this.asyncTestMethod( TestContext.Current.CancellationToken ); - this.MockInterceptDbCommand.Received().Invoke( - Arg.Is(cmd => cmd.CommandType == CommandType.StoredProcedure), - Arg.Any>() - ); + this.MockInterceptDbCommand.Received() + .Invoke( + Arg.Is(cmd => cmd.CommandType == CommandType.StoredProcedure), + Arg.Any>() + ); } [Fact] @@ -68,10 +83,11 @@ await this.asyncTestMethod( TestContext.Current.CancellationToken ); - this.MockInterceptDbCommand.Received().Invoke( - Arg.Is(cmd => cmd.Transaction == transaction), - Arg.Any>() - ); + this.MockInterceptDbCommand.Received() + .Invoke( + Arg.Is(cmd => cmd.Transaction == transaction), + Arg.Any>() + ); } [Fact] @@ -88,10 +104,11 @@ public void SyncMethod_ShouldUseCommandTimeout() TestContext.Current.CancellationToken ); - this.MockInterceptDbCommand.Received().Invoke( - Arg.Is(cmd => cmd.CommandTimeout == (int)timeout.TotalSeconds), - Arg.Any>() - ); + this.MockInterceptDbCommand.Received() + .Invoke( + Arg.Is(cmd => cmd.CommandTimeout == (int)timeout.TotalSeconds), + Arg.Any>() + ); } [Fact] @@ -106,10 +123,11 @@ public void SyncMethod_ShouldUseCommandType() TestContext.Current.CancellationToken ); - this.MockInterceptDbCommand.Received().Invoke( - Arg.Is(cmd => cmd.CommandType == CommandType.StoredProcedure), - Arg.Any>() - ); + this.MockInterceptDbCommand.Received() + .Invoke( + Arg.Is(cmd => cmd.CommandType == CommandType.StoredProcedure), + Arg.Any>() + ); } [Fact] @@ -126,17 +144,29 @@ public void SyncMethod_ShouldUseTransaction() TestContext.Current.CancellationToken ); - this.MockInterceptDbCommand.Received().Invoke( - Arg.Is(cmd => cmd.Transaction == transaction), - Arg.Any>() - ); + this.MockInterceptDbCommand.Received() + .Invoke( + Arg.Is(cmd => cmd.Transaction == transaction), + Arg.Any>() + ); } - private readonly - Func - asyncTestMethod = asyncTestMethod; - - private readonly - Action - syncTestMethod = syncTestMethod; + private readonly Func< + DbConnection, + InterpolatedSqlStatement, + DbTransaction?, + TimeSpan?, + CommandType, + CancellationToken, + Task + > asyncTestMethod = asyncTestMethod; + + private readonly Action< + DbConnection, + InterpolatedSqlStatement, + DbTransaction?, + TimeSpan?, + CommandType, + CancellationToken + > syncTestMethod = syncTestMethod; } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithPrivateParameterlessConstructor.cs b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithPrivateParameterlessConstructor.cs index ee5febd..4525b13 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithPrivateParameterlessConstructor.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithPrivateParameterlessConstructor.cs @@ -2,7 +2,5 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public record EntityWithPrivateParameterlessConstructor : Entity { - private EntityWithPrivateParameterlessConstructor() - { - } + private EntityWithPrivateParameterlessConstructor() { } } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionA.cs b/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionA.cs index 3386734..e6aaf60 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionA.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionA.cs @@ -9,38 +9,30 @@ public class FakeConnectionA : DbConnection public override string ConnectionString { get; set; } /// - public override string Database => - null!; + public override string Database => null!; /// - public override string DataSource => - null!; + public override string DataSource => null!; /// - public override string ServerVersion => - null!; + public override string ServerVersion => null!; /// - public override ConnectionState State => - ConnectionState.Closed; + public override ConnectionState State => ConnectionState.Closed; /// - public override void ChangeDatabase(string databaseName) => - throw new NotImplementedException(); + public override void ChangeDatabase(string databaseName) => throw new NotImplementedException(); /// - public override void Close() => - throw new NotImplementedException(); + public override void Close() => throw new NotImplementedException(); /// - public override void Open() => - throw new NotImplementedException(); + public override void Open() => throw new NotImplementedException(); /// protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) => throw new NotImplementedException(); /// - protected override DbCommand CreateDbCommand() => - throw new NotImplementedException(); + protected override DbCommand CreateDbCommand() => throw new NotImplementedException(); } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionB.cs b/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionB.cs index 245b249..b140e98 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionB.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionB.cs @@ -9,38 +9,30 @@ public class FakeConnectionB : DbConnection public override string ConnectionString { get; set; } /// - public override string Database => - null!; + public override string Database => null!; /// - public override string DataSource => - null!; + public override string DataSource => null!; /// - public override string ServerVersion => - null!; + public override string ServerVersion => null!; /// - public override ConnectionState State => - ConnectionState.Closed; + public override ConnectionState State => ConnectionState.Closed; /// - public override void ChangeDatabase(string databaseName) => - throw new NotImplementedException(); + public override void ChangeDatabase(string databaseName) => throw new NotImplementedException(); /// - public override void Close() => - throw new NotImplementedException(); + public override void Close() => throw new NotImplementedException(); /// - public override void Open() => - throw new NotImplementedException(); + public override void Open() => throw new NotImplementedException(); /// protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) => throw new NotImplementedException(); /// - protected override DbCommand CreateDbCommand() => - throw new NotImplementedException(); + protected override DbCommand CreateDbCommand() => throw new NotImplementedException(); } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionC.cs b/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionC.cs index c68c1c4..907751d 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionC.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionC.cs @@ -9,38 +9,30 @@ public class FakeConnectionC : FakeConnectionA public override string ConnectionString { get; set; } /// - public override string Database => - null!; + public override string Database => null!; /// - public override string DataSource => - null!; + public override string DataSource => null!; /// - public override string ServerVersion => - null!; + public override string ServerVersion => null!; /// - public override ConnectionState State => - ConnectionState.Closed; + public override ConnectionState State => ConnectionState.Closed; /// - public override void ChangeDatabase(string databaseName) => - throw new NotImplementedException(); + public override void ChangeDatabase(string databaseName) => throw new NotImplementedException(); /// - public override void Close() => - throw new NotImplementedException(); + public override void Close() => throw new NotImplementedException(); /// - public override void Open() => - throw new NotImplementedException(); + public override void Open() => throw new NotImplementedException(); /// protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) => throw new NotImplementedException(); /// - protected override DbCommand CreateDbCommand() => - throw new NotImplementedException(); + protected override DbCommand CreateDbCommand() => throw new NotImplementedException(); } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/Generate.cs b/tests/DbConnectionPlus.UnitTests/TestData/Generate.cs index d7ab331..46c870b 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/Generate.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/Generate.cs @@ -33,77 +33,70 @@ static Generate() fixture.Register(() => characters[faker.Random.Int(0, characters.Length - 1)]); fixture.Register(() => faker.Date.PastDateOnly()); fixture.Register(() => - { - var dateTime = faker.Date.Past(); - - // We limit to seconds precision because not all database systems support a higher precision. - return new( - dateTime.Year, - dateTime.Month, - dateTime.Day, - dateTime.Hour, - dateTime.Minute, - dateTime.Second, - DateTimeKind.Local - ); - } - ); + { + var dateTime = faker.Date.Past(); + + // We limit to seconds precision because not all database systems support a higher precision. + return new( + dateTime.Year, + dateTime.Month, + dateTime.Day, + dateTime.Hour, + dateTime.Minute, + dateTime.Second, + DateTimeKind.Local + ); + }); fixture.Register(() => - { - var dateTimeOffset = faker.Date.PastOffset(); - - // We limit to seconds precision because not all database systems support a higher precision. - return new( - dateTimeOffset.Year, - dateTimeOffset.Month, - dateTimeOffset.Day, - dateTimeOffset.Hour, - dateTimeOffset.Minute, - dateTimeOffset.Second, - dateTimeOffset.Offset - ); - } - ); + { + var dateTimeOffset = faker.Date.PastOffset(); + + // We limit to seconds precision because not all database systems support a higher precision. + return new( + dateTimeOffset.Year, + dateTimeOffset.Month, + dateTimeOffset.Day, + dateTimeOffset.Hour, + dateTimeOffset.Minute, + dateTimeOffset.Second, + dateTimeOffset.Offset + ); + }); fixture.Register(() => - { - // We limit to 10 fractional digits because not all database systems support a higher precision. - return Math.Round(faker.Random.Decimal(0, 999), 10); - } - ); + { + // We limit to 10 fractional digits because not all database systems support a higher precision. + return Math.Round(faker.Random.Decimal(0, 999), 10); + }); fixture.Register(() => - { - // We limit to 3 fractional digits because not all database systems support a higher precision. - return Math.Round(faker.Random.Double(0, 999), 3); - } - ); + { + // We limit to 3 fractional digits because not all database systems support a higher precision. + return Math.Round(faker.Random.Double(0, 999), 3); + }); fixture.Register(() => faker.Random.Guid()); fixture.Register(() => faker.Random.Short()); fixture.Register(() => faker.Random.Int()); fixture.Register(() => Interlocked.Increment(ref entityId)); fixture.Register(() => - { - // We limit to 3 fractional digits because not all database systems support a higher precision. - return (float)Math.Round(faker.Random.Float(0, 999), 3); - } - ); + { + // We limit to 3 fractional digits because not all database systems support a higher precision. + return (float)Math.Round(faker.Random.Float(0, 999), 3); + }); fixture.Register(() => faker.Lorem.Sentence()); fixture.Register(() => faker.Random.Enum()); fixture.Register(() => - { - var timeOnly = faker.Date.RecentTimeOnly(); + { + var timeOnly = faker.Date.RecentTimeOnly(); - // We limit to seconds precision because not all database systems support a higher precision. - return new(timeOnly.Hour, timeOnly.Minute, timeOnly.Second); - } - ); + // We limit to seconds precision because not all database systems support a higher precision. + return new(timeOnly.Hour, timeOnly.Minute, timeOnly.Second); + }); fixture.Register(() => - { - var timeSpan = faker.Date.Timespan(new TimeSpan(0, 23, 59, 59)); + { + var timeSpan = faker.Date.Timespan(new TimeSpan(0, 23, 59, 59)); - // We limit to seconds precision because not all database systems support a higher precision. - return new(timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds); - } - ); + // We limit to seconds precision because not all database systems support a higher precision. + return new(timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds); + }); #pragma warning disable S2930 var cancellationTokenSource = new CancellationTokenSource(); @@ -119,8 +112,7 @@ static Generate() /// Generates an ID. /// /// An ID. - public static long Id() => - Interlocked.Increment(ref entityId); + public static long Id() => Interlocked.Increment(ref entityId); /// /// Generates the specified number of IDs. @@ -141,8 +133,7 @@ public static List Ids(int? numberOfIds = null) => /// /// A list of objects containing the same data as . /// - public static List MapTo(IEnumerable objects) => - objects.Adapt>(); + public static List MapTo(IEnumerable objects) => objects.Adapt>(); /// /// Maps to an instance of containing the same data. @@ -152,8 +143,7 @@ public static List MapTo(IEnumerable objects) => /// /// An instance of containing the same data as . /// - public static TTarget MapTo(object obj) => - obj.Adapt(); + public static TTarget MapTo(object obj) => obj.Adapt(); /// /// Generates a list of instances of the type populated with test data. @@ -229,7 +219,7 @@ public static object ScalarValue() => 11 => fixture.Create(), 12 => fixture.Create(), 13 => fixture.Create(), - _ => fixture.Create() + _ => fixture.Create(), }; /// @@ -247,8 +237,7 @@ public static T Single() /// Generates a random number between 5 and 15. /// /// A random number between 5 and 15. - public static int SmallNumber() => - faker.Random.Int(5, 15); + public static int SmallNumber() => faker.Random.Int(5, 15); /// /// Creates a copy of where all properties except the key and concurrency token @@ -286,8 +275,7 @@ public static T UpdateFor(T entity) /// A list with copies of where all properties except key and concurrency token /// properties have new values. /// - public static List UpdateFor(List entities) => - [.. entities.Select(UpdateFor)]; + public static List UpdateFor(List entities) => [.. entities.Select(UpdateFor)]; /// /// Copies the values of all key and concurrency token properties from @@ -300,10 +288,9 @@ private static void CopyKeysAndConcurrencyTokens(T sourceEntity, T targetEnti { var metadata = EntityHelper.GetEntityTypeMetadata(typeof(T)); - var propertiesToCopy = - metadata.KeyProperties - .Concat(metadata.ConcurrencyTokenProperties) - .Concat(metadata.RowVersionProperties); + var propertiesToCopy = metadata + .KeyProperties.Concat(metadata.ConcurrencyTokenProperties) + .Concat(metadata.RowVersionProperties); foreach (var property in propertiesToCopy) { @@ -343,9 +330,7 @@ public object Create(object request, ISpecimenContext context) entityTypeMetadata.AllPropertiesByPropertyName.TryGetValue( propertyInfo.Name, out var propertyMetadata - ) - && - propertyMetadata.IsIgnored + ) && propertyMetadata.IsIgnored ) { return new OmitSpecimen(); diff --git a/tests/DbConnectionPlus.UnitTests/TestData/ItemWithPrivateParameterlessConstructor.cs b/tests/DbConnectionPlus.UnitTests/TestData/ItemWithPrivateParameterlessConstructor.cs index 4affe93..d28ad5f 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/ItemWithPrivateParameterlessConstructor.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/ItemWithPrivateParameterlessConstructor.cs @@ -4,7 +4,5 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public sealed class ItemWithPrivateParameterlessConstructor { - private ItemWithPrivateParameterlessConstructor() - { - } + private ItemWithPrivateParameterlessConstructor() { } } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/MappingTestEntityFluentApi.cs b/tests/DbConnectionPlus.UnitTests/TestData/MappingTestEntityFluentApi.cs index 446d952..d7ab793 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/MappingTestEntityFluentApi.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/MappingTestEntityFluentApi.cs @@ -18,47 +18,39 @@ public record MappingTestEntityFluentApi /// public static void Configure() => DbConnectionExtensions.Configure(config => - { - config.Entity() - .ToTable("MappingTestEntity"); + { + config.Entity().ToTable("MappingTestEntity"); - config.Entity() - .Property(a => a.Computed_) - .HasColumnName("Computed") - .IsComputed(); + config + .Entity() + .Property(a => a.Computed_) + .HasColumnName("Computed") + .IsComputed(); - config.Entity() - .Property(a => a.ConcurrencyToken_) - .HasColumnName("ConcurrencyToken") - .IsConcurrencyToken(); + config + .Entity() + .Property(a => a.ConcurrencyToken_) + .HasColumnName("ConcurrencyToken") + .IsConcurrencyToken(); - config.Entity() - .Property(a => a.Identity_) - .HasColumnName("Identity") - .IsIdentity(); + config + .Entity() + .Property(a => a.Identity_) + .HasColumnName("Identity") + .IsIdentity(); - config.Entity() - .Property(a => a.Key1_) - .HasColumnName("Key1") - .IsKey(); + config.Entity().Property(a => a.Key1_).HasColumnName("Key1").IsKey(); - config.Entity() - .Property(a => a.Key2_) - .HasColumnName("Key2") - .IsKey(); + config.Entity().Property(a => a.Key2_).HasColumnName("Key2").IsKey(); - config.Entity() - .Property(a => a.Value_) - .HasColumnName("Value"); + config.Entity().Property(a => a.Value_).HasColumnName("Value"); - config.Entity() - .Property(a => a.NotMapped) - .IsIgnored(); + config.Entity().Property(a => a.NotMapped).IsIgnored(); - config.Entity() - .Property(a => a.RowVersion_) - .HasColumnName("RowVersion") - .IsRowVersion(); - } - ); + config + .Entity() + .Property(a => a.RowVersion_) + .HasColumnName("RowVersion") + .IsRowVersion(); + }); } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/NotAValueTuple.cs b/tests/DbConnectionPlus.UnitTests/TestData/NotAValueTuple.cs index 6c69fea..e7d8304 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/NotAValueTuple.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/NotAValueTuple.cs @@ -6,18 +6,14 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public struct NotAValueTuple : IStructuralEquatable, IStructuralComparable, IComparable { /// - public int CompareTo(object? other, IComparer comparer) => - throw new NotImplementedException(); + public int CompareTo(object? other, IComparer comparer) => throw new NotImplementedException(); /// - public int CompareTo(object? obj) => - throw new NotImplementedException(); + public int CompareTo(object? obj) => throw new NotImplementedException(); /// - public bool Equals(object? other, IEqualityComparer comparer) => - throw new NotImplementedException(); + public bool Equals(object? other, IEqualityComparer comparer) => throw new NotImplementedException(); /// - public int GetHashCode(IEqualityComparer comparer) => - throw new NotImplementedException(); + public int GetHashCode(IEqualityComparer comparer) => throw new NotImplementedException(); } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/TestEnum.cs b/tests/DbConnectionPlus.UnitTests/TestData/TestEnum.cs index 988010a..ef83dce 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/TestEnum.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/TestEnum.cs @@ -8,5 +8,5 @@ public enum TestEnum Value2 = 2, Value3 = 3, Value4 = 4, - Value5 = 5 + Value5 = 5, } diff --git a/tests/DbConnectionPlus.UnitTests/Trimming/ILLinkDescriptorsTests.cs b/tests/DbConnectionPlus.UnitTests/Trimming/ILLinkDescriptorsTests.cs index 56a4515..ca0078d 100644 --- a/tests/DbConnectionPlus.UnitTests/Trimming/ILLinkDescriptorsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Trimming/ILLinkDescriptorsTests.cs @@ -24,8 +24,10 @@ public class ILLinkDescriptorsTests : UnitTestsBase { [Fact] public void CoreAssembly_ShouldEmbedTheILLinkDescriptor() => - typeof(DbConnectionExtensions).Assembly.GetManifestResourceNames() - .Should().Contain(ILLinkDescriptorsResourceName); + typeof(DbConnectionExtensions) + .Assembly.GetManifestResourceNames() + .Should() + .Contain(ILLinkDescriptorsResourceName); [Theory] [InlineData(1)] @@ -44,14 +46,14 @@ public void ILLinkDescriptor_ShouldPreserveAllMembersOfEveryValueTupleArity(int .Select(a => (string?)a.Attribute("fullname")) .ToList(); - preservedTypes - .Should().Contain($"System.ValueTuple`{arity}"); + preservedTypes.Should().Contain($"System.ValueTuple`{arity}"); } private static XDocument ReadDescriptor() { - using var stream = typeof(DbConnectionExtensions).Assembly - .GetManifestResourceStream(ILLinkDescriptorsResourceName)!; + using var stream = typeof(DbConnectionExtensions).Assembly.GetManifestResourceStream( + ILLinkDescriptorsResourceName + )!; return XDocument.Load(stream); } diff --git a/tests/DbConnectionPlus.UnitTests/UnitTestsBase.cs b/tests/DbConnectionPlus.UnitTests/UnitTestsBase.cs index 4ab4f0c..4d3e346 100644 --- a/tests/DbConnectionPlus.UnitTests/UnitTestsBase.cs +++ b/tests/DbConnectionPlus.UnitTests/UnitTestsBase.cs @@ -22,9 +22,9 @@ public UnitTestsBase() // Ensure consistent culture for tests. CultureInfo.CurrentCulture = CultureInfo.CurrentUICulture = - Thread.CurrentThread.CurrentCulture = - Thread.CurrentThread.CurrentUICulture = - new("en-US"); + Thread.CurrentThread.CurrentCulture = + Thread.CurrentThread.CurrentUICulture = + new("en-US"); this.MockDatabaseAdapter = Substitute.For(); this.MockEntityManipulator = Substitute.For(); @@ -50,73 +50,67 @@ public UnitTestsBase() this.MockTemporaryTableBuilder = Substitute.For(); this.MockTemporaryTableBuilder.BuildTemporaryTable( - Arg.Any(), - Arg.Any(), - Arg.Any(), - Arg.Any(), - Arg.Any(), - Arg.Any() - ).Returns(new TemporaryTableDisposer(Substitute.For(), Substitute.For>())); + Arg.Any(), + Arg.Any(), + Arg.Any(), + Arg.Any(), + Arg.Any(), + Arg.Any() + ) + .Returns(new TemporaryTableDisposer(Substitute.For(), Substitute.For>())); this.MockTemporaryTableBuilder.BuildTemporaryTableAsync( - Arg.Any(), - Arg.Any(), - Arg.Any(), - Arg.Any(), - Arg.Any(), - Arg.Any() - ).Returns(new TemporaryTableDisposer(Substitute.For(), Substitute.For>())); + Arg.Any(), + Arg.Any(), + Arg.Any(), + Arg.Any(), + Arg.Any(), + Arg.Any() + ) + .Returns(new TemporaryTableDisposer(Substitute.For(), Substitute.For>())); this.MockDatabaseAdapter.SupportsTemporaryTables(Arg.Any()).Returns(true); this.MockDatabaseAdapter.TemporaryTableBuilder.Returns(this.MockTemporaryTableBuilder); - this.MockDatabaseAdapter.QuoteIdentifier(Arg.Any()) - .Returns(info => $"[{info.ArgAt(0)}]"); + this.MockDatabaseAdapter.QuoteIdentifier(Arg.Any()).Returns(info => $"[{info.ArgAt(0)}]"); this.MockDatabaseAdapter.QuoteTemporaryTableName(Arg.Any(), this.MockDbConnection) .Returns(info => $"[#{info.ArgAt(0)}]"); - this.MockDatabaseAdapter.FormatParameterName(Arg.Any()) - .Returns(info => $"@{info.ArgAt(0)}"); + this.MockDatabaseAdapter.FormatParameterName(Arg.Any()).Returns(info => $"@{info.ArgAt(0)}"); - this.MockDatabaseAdapter - .When(a => a.BindParameterValue(Arg.Any(), Arg.Any())) + this.MockDatabaseAdapter.When(a => a.BindParameterValue(Arg.Any(), Arg.Any())) .Do(info => - { - var parameter = info.ArgAt(0); - var value = info.ArgAt(1); + { + var parameter = info.ArgAt(0); + var value = info.ArgAt(1); - if (value is Enum enumValue) - { - parameter.DbType = DbConnectionPlusConfiguration.Instance.EnumSerializationMode switch - { - EnumSerializationMode.Integers => - DbType.Int32, - - EnumSerializationMode.Strings => - DbType.String, - - _ => - throw new NotSupportedException( - $"The {nameof(EnumSerializationMode)} " + - $"{DbConnectionPlusConfiguration.Instance.EnumSerializationMode.ToDebugString()} " + - "is not supported." - ) - }; - - parameter.Value = - EnumSerializer.SerializeEnum( - enumValue, - DbConnectionPlusConfiguration.Instance.EnumSerializationMode - ); - } - else + if (value is Enum enumValue) + { + parameter.DbType = DbConnectionPlusConfiguration.Instance.EnumSerializationMode switch { - parameter.Value = value ?? DBNull.Value; - } + EnumSerializationMode.Integers => DbType.Int32, + + EnumSerializationMode.Strings => DbType.String, + + _ => throw new NotSupportedException( + $"The {nameof(EnumSerializationMode)} " + + $"{DbConnectionPlusConfiguration.Instance.EnumSerializationMode.ToDebugString()} " + + "is not supported." + ), + }; + + parameter.Value = EnumSerializer.SerializeEnum( + enumValue, + DbConnectionPlusConfiguration.Instance.EnumSerializationMode + ); + } + else + { + parameter.Value = value ?? DBNull.Value; } - ); + }); this.MockDatabaseAdapter.EntityManipulator.Returns(this.MockEntityManipulator); @@ -126,12 +120,13 @@ public UnitTestsBase() DbConnectionPlusConfiguration.Instance = new() { EnumSerializationMode = EnumSerializationMode.Strings, - InterceptDbCommand = this.MockInterceptDbCommand + InterceptDbCommand = this.MockInterceptDbCommand, }; EntityHelper.ResetEntityTypeMetadataCache(); OracleDatabaseAdapter.AllowTemporaryTables = false; - typeof(DbConnectionPlusConfiguration).GetMethod(nameof(DbConnectionPlusConfiguration.RegisterDatabaseAdapter))! + typeof(DbConnectionPlusConfiguration) + .GetMethod(nameof(DbConnectionPlusConfiguration.RegisterDatabaseAdapter))! .MakeGenericMethod(this.MockDbConnection.GetType()) .Invoke(DbConnectionPlusConfiguration.Instance, [this.MockDatabaseAdapter]); } diff --git a/tests/package-consumption/AllAdaptersConsumer/GlobalUsings.cs b/tests/package-consumption/AllAdaptersConsumer/GlobalUsings.cs index 1e6981f..76b40b1 100644 --- a/tests/package-consumption/AllAdaptersConsumer/GlobalUsings.cs +++ b/tests/package-consumption/AllAdaptersConsumer/GlobalUsings.cs @@ -2,5 +2,5 @@ global using System.Data.Common; global using Microsoft.Data.Sqlite; global using RentADeveloper.DbConnectionPlus.Configuration; -global using RentADeveloper.DbConnectionPlus.PackageConsumption; global using static RentADeveloper.DbConnectionPlus.DbConnectionExtensions; +global using RentADeveloper.DbConnectionPlus.PackageConsumption; diff --git a/tests/package-consumption/AllAdaptersConsumer/Program.cs b/tests/package-consumption/AllAdaptersConsumer/Program.cs index 23bbf8e..e17b079 100644 --- a/tests/package-consumption/AllAdaptersConsumer/Program.cs +++ b/tests/package-consumption/AllAdaptersConsumer/Program.cs @@ -99,12 +99,7 @@ private static void RegisterEveryAdapter() DbConnectionPlusConfiguration? configured = null; Configure(configuration => - configured = configuration - .UseMySql() - .UseOracle() - .UsePostgreSql() - .UseSqlite() - .UseSqlServer() + configured = configuration.UseMySql().UseOracle().UsePostgreSql().UseSqlite().UseSqlServer() ); Check.True("the five UseXxx calls chain and return the configuration", configured is not null); @@ -170,7 +165,8 @@ private static void AssertOneSharedLibraryAssembly() { Check.Section("3. One shared DbConnectionPlus assembly, not one copy per adapter"); - var libraryAssemblies = AppDomain.CurrentDomain.GetAssemblies() + var libraryAssemblies = AppDomain + .CurrentDomain.GetAssemblies() .Select(assembly => assembly.GetName()) .Where(name => name.Name == "RentADeveloper.DbConnectionPlus") .ToList(); diff --git a/tests/package-consumption/AotConsumer/GlobalUsings.cs b/tests/package-consumption/AotConsumer/GlobalUsings.cs index 5ce6699..e0af278 100644 --- a/tests/package-consumption/AotConsumer/GlobalUsings.cs +++ b/tests/package-consumption/AotConsumer/GlobalUsings.cs @@ -2,6 +2,6 @@ global using System.Data.Common; global using Microsoft.Data.Sqlite; global using RentADeveloper.DbConnectionPlus.Configuration; +global using static RentADeveloper.DbConnectionPlus.DbConnectionExtensions; global using RentADeveloper.DbConnectionPlus.PackageConsumption; global using RentADeveloper.DbConnectionPlus.SqlStatements; -global using static RentADeveloper.DbConnectionPlus.DbConnectionExtensions; diff --git a/tests/package-consumption/AotConsumer/Model.cs b/tests/package-consumption/AotConsumer/Model.cs index 8c62db5..52ace2c 100644 --- a/tests/package-consumption/AotConsumer/Model.cs +++ b/tests/package-consumption/AotConsumer/Model.cs @@ -38,7 +38,7 @@ public enum SmokeStatus Active = 1, /// The entity is retained for reference only. - Archived = 2 + Archived = 2, } /// @@ -134,7 +134,7 @@ public enum FlatTupleNumericEnum FlatNumericChosen = 71, /// Never stored. Present so that an off-by-one bind is visible. - FlatNumericOther = 72 + FlatNumericOther = 72, } /// @@ -150,7 +150,7 @@ public enum NestedTupleNumericEnum NestedNumericChosen = 81, /// Never stored. Present so that an off-by-one bind is visible. - NestedNumericOther = 82 + NestedNumericOther = 82, } /// @@ -166,7 +166,7 @@ public enum FlatTupleNamedEnum FlatNamedChosen = 91, /// Never stored. Present so that a parse landing on the wrong member is visible. - FlatNamedOther = 92 + FlatNamedOther = 92, } /// @@ -184,7 +184,7 @@ public enum NestedTupleNamedEnum NestedNamedChosen = 101, /// Never stored. Present so that a parse landing on the wrong member is visible. - NestedNamedOther = 102 + NestedNamedOther = 102, } /// diff --git a/tests/package-consumption/AotConsumer/Program.cs b/tests/package-consumption/AotConsumer/Program.cs index 7f15268..5c06da5 100644 --- a/tests/package-consumption/AotConsumer/Program.cs +++ b/tests/package-consumption/AotConsumer/Program.cs @@ -32,10 +32,7 @@ public static class Program /// Zero if every assertion passed, otherwise one. public static Int32 Main() { - var databasePath = Path.Combine( - Path.GetTempPath(), - $"dbconnectionplus-aot-consumer-{Guid.NewGuid():N}.db" - ); + var databasePath = Path.Combine(Path.GetTempPath(), $"dbconnectionplus-aot-consumer-{Guid.NewGuid():N}.db"); Console.WriteLine(new String('=', 100)); Console.WriteLine("DbConnectionPlus - Native AOT package consumer"); diff --git a/tests/package-consumption/AotConsumer/SmokeCases.cs b/tests/package-consumption/AotConsumer/SmokeCases.cs index 7f08df1..4422820 100644 --- a/tests/package-consumption/AotConsumer/SmokeCases.cs +++ b/tests/package-consumption/AotConsumer/SmokeCases.cs @@ -25,7 +25,7 @@ public static class SmokeCases CreatedAt = new DateTime(2026, 8, 11, 12, 34, 56, DateTimeKind.Unspecified), ExternalId = new Guid("6f9619ff-8b86-d011-b42d-00cf4fc964ff"), Status = SmokeStatus.Active, - Quantity = 42 + Quantity = 42, }; /// The primary key of the single row the enum cases read. @@ -118,13 +118,15 @@ public static void QueryEntity(DbConnection connection) { Check.Section("2. Query - property-setter strategy, every property asserted"); - var entity = connection.Query( - $""" - SELECT Id, Name, Balance, IsActive, CreatedAt, ExternalId, Status, Quantity - FROM SmokeEntity - WHERE Id = {ExpectedEntity.Id} - """ - ).Single(); + var entity = connection + .Query( + $""" + SELECT Id, Name, Balance, IsActive, CreatedAt, ExternalId, Status, Quantity + FROM SmokeEntity + WHERE Id = {ExpectedEntity.Id} + """ + ) + .Single(); Check.Equal("Id", ExpectedEntity.Id, entity.Id); Check.Equal("Name", ExpectedEntity.Name, entity.Name); @@ -152,9 +154,9 @@ public static void QueryEntityWithADifferentSelectList(DbConnection connection) { Check.Section("3. Query - different result-set shape (reordered, partial SELECT list)"); - var entity = connection.Query( - $"SELECT Quantity, Name, Id FROM SmokeEntity WHERE Id = {ExpectedEntity.Id}" - ).Single(); + var entity = connection + .Query($"SELECT Quantity, Name, Id FROM SmokeEntity WHERE Id = {ExpectedEntity.Id}") + .Single(); Check.Equal("Quantity", ExpectedEntity.Quantity, entity.Quantity); Check.Equal("Name", ExpectedEntity.Name, entity.Name); @@ -169,9 +171,9 @@ public static void QueryImmutableEntity(DbConnection connection) { Check.Section("4. Query - constructor injection"); - var entity = connection.Query( - $"SELECT Id, Name, Balance FROM SmokeEntity WHERE Id = {ExpectedEntity.Id}" - ).Single(); + var entity = connection + .Query($"SELECT Id, Name, Balance FROM SmokeEntity WHERE Id = {ExpectedEntity.Id}") + .Single(); Check.Equal("Id", ExpectedEntity.Id, entity.Id); Check.Equal("Name", ExpectedEntity.Name, entity.Name); @@ -184,9 +186,11 @@ public static void QueryValueTuple(DbConnection connection) { Check.Section("5. Query<(Int64, String, Decimal)> - value tuple"); - var (id, name, balance) = connection.Query<(Int64 Id, String Name, Decimal Balance)>( - $"SELECT Id, Name, Balance FROM SmokeEntity WHERE Id = {ExpectedEntity.Id}" - ).Single(); + var (id, name, balance) = connection + .Query<(Int64 Id, String Name, Decimal Balance)>( + $"SELECT Id, Name, Balance FROM SmokeEntity WHERE Id = {ExpectedEntity.Id}" + ) + .Single(); Check.Equal("Id", ExpectedEntity.Id, id); Check.Equal("Name", ExpectedEntity.Name, name); @@ -208,13 +212,15 @@ public static void QueryNestedValueTuple(DbConnection connection) { Check.Section("6. Query<(...8 fields)> - nested value tuple (TRest)"); - var tuple = connection.Query<(Int64 A, Int64 B, Int64 C, Int64 D, Int64 E, Int64 F, Int64 G, String H)>( - $""" - SELECT Id AS A, Quantity AS B, Id AS C, Quantity AS D, Id AS E, Quantity AS F, Id AS G, Name AS H - FROM SmokeEntity - WHERE Id = {ExpectedEntity.Id} - """ - ).Single(); + var tuple = connection + .Query<(Int64 A, Int64 B, Int64 C, Int64 D, Int64 E, Int64 F, Int64 G, String H)>( + $""" + SELECT Id AS A, Quantity AS B, Id AS C, Quantity AS D, Id AS E, Quantity AS F, Id AS G, Name AS H + FROM SmokeEntity + WHERE Id = {ExpectedEntity.Id} + """ + ) + .Single(); Check.Equal("field 1", ExpectedEntity.Id, tuple.A); Check.Equal("field 2", (Int64)ExpectedEntity.Quantity, tuple.B); @@ -249,9 +255,7 @@ public static void SingleColumnTemporaryTable(DbConnection connection) var values = new List { 10, 20, 30 }; - var read = connection.Query( - $"SELECT Value FROM {TemporaryTable(values)} ORDER BY Value" - ).ToList(); + var read = connection.Query($"SELECT Value FROM {TemporaryTable(values)} ORDER BY Value").ToList(); Check.Equal("three values round-trip", 3, read.Count); Check.True("the values are unchanged", read.SequenceEqual(values)); @@ -272,12 +276,10 @@ public static void MultiColumnTemporaryTable(DbConnection connection) var items = new List { new() { Id = 1, Label = "one" }, - new() { Id = 2, Label = "two" } + new() { Id = 2, Label = "two" }, }; - var read = connection.Query( - $"SELECT Id, Label FROM {TemporaryTable(items)} ORDER BY Id" - ).ToList(); + var read = connection.Query($"SELECT Id, Label FROM {TemporaryTable(items)} ORDER BY Id").ToList(); Check.Equal("two items round-trip", 2, read.Count); Check.Equal("item 1 Id", 1L, read[0].Id); @@ -308,9 +310,10 @@ public static void ZeroBindingGuard(DbConnection connection) Check.Throws( "a result set matching no property throws instead of returning default-valued entities", "could be mapped to a writable property of the entity type", - () => connection.Query( - $"SELECT 1 AS Alpha, 2 AS Beta FROM SmokeEntity WHERE Id = {ExpectedEntity.Id}" - ).ToList() + () => + connection + .Query($"SELECT 1 AS Alpha, 2 AS Beta FROM SmokeEntity WHERE Id = {ExpectedEntity.Id}") + .ToList() ); } @@ -331,9 +334,11 @@ public static void QueryValueTupleWithANumericEnum(DbConnection connection) { Check.Section("11. Query<(Int64, enum)> - enum field of a flat value tuple, from an INTEGER column"); - var (id, status) = connection.Query<(Int64 Id, FlatTupleNumericEnum Status)>( - $"SELECT Id, FlatNumeric AS Status FROM SmokeEnum WHERE Id = {EnumRowId}" - ).Single(); + var (id, status) = connection + .Query<(Int64 Id, FlatTupleNumericEnum Status)>( + $"SELECT Id, FlatNumeric AS Status FROM SmokeEnum WHERE Id = {EnumRowId}" + ) + .Single(); Check.Equal("Id", EnumRowId, id); Check.Equal("the enum field binds the stored value", 71, (Int32)status); @@ -355,15 +360,15 @@ public static void QueryNestedValueTupleWithANumericEnum(DbConnection connection { Check.Section("12. Query<(...8 fields)> - enum field nested in TRest, from an INTEGER column"); - var tuple = connection.Query<( - Int64 A, Int64 B, Int64 C, Int64 D, Int64 E, Int64 F, Int64 G, NestedTupleNumericEnum H - )>( - $""" - SELECT Id AS A, Id AS B, Id AS C, Id AS D, Id AS E, Id AS F, Id AS G, NestedNumeric AS H - FROM SmokeEnum - WHERE Id = {EnumRowId} - """ - ).Single(); + var tuple = connection + .Query<(Int64 A, Int64 B, Int64 C, Int64 D, Int64 E, Int64 F, Int64 G, NestedTupleNumericEnum H)>( + $""" + SELECT Id AS A, Id AS B, Id AS C, Id AS D, Id AS E, Id AS F, Id AS G, NestedNumeric AS H + FROM SmokeEnum + WHERE Id = {EnumRowId} + """ + ) + .Single(); Check.Equal("field 1", EnumRowId, tuple.A); Check.Equal("field 8 (enum nested in TRest) binds the stored value", 81, (Int32)tuple.H); @@ -385,9 +390,11 @@ public static void QueryValueTupleWithANamedEnum(DbConnection connection) { Check.Section("13. Query<(Int64, enum)> - enum field of a flat value tuple, parsed from a TEXT column"); - var (id, status) = connection.Query<(Int64 Id, FlatTupleNamedEnum Status)>( - $"SELECT Id, FlatNamed AS Status FROM SmokeEnum WHERE Id = {EnumRowId}" - ).Single(); + var (id, status) = connection + .Query<(Int64 Id, FlatTupleNamedEnum Status)>( + $"SELECT Id, FlatNamed AS Status FROM SmokeEnum WHERE Id = {EnumRowId}" + ) + .Single(); Check.Equal("Id", EnumRowId, id); Check.Equal("the name in the column parsed to the right member", 91, (Int32)status); @@ -411,15 +418,15 @@ public static void QueryNestedValueTupleWithANamedEnum(DbConnection connection) { Check.Section("14. Query<(...8 fields)> - enum field nested in TRest, parsed from a TEXT column"); - var tuple = connection.Query<( - Int64 A, Int64 B, Int64 C, Int64 D, Int64 E, Int64 F, Int64 G, NestedTupleNamedEnum H - )>( - $""" - SELECT Id AS A, Id AS B, Id AS C, Id AS D, Id AS E, Id AS F, Id AS G, NestedNamed AS H - FROM SmokeEnum - WHERE Id = {EnumRowId} - """ - ).Single(); + var tuple = connection + .Query<(Int64 A, Int64 B, Int64 C, Int64 D, Int64 E, Int64 F, Int64 G, NestedTupleNamedEnum H)>( + $""" + SELECT Id AS A, Id AS B, Id AS C, Id AS D, Id AS E, Id AS F, Id AS G, NestedNamed AS H + FROM SmokeEnum + WHERE Id = {EnumRowId} + """ + ) + .Single(); Check.Equal("field 1", EnumRowId, tuple.A); Check.Equal("field 8 (enum nested in TRest) parsed to the right member", 101, (Int32)tuple.H); diff --git a/tests/package-consumption/Check.cs b/tests/package-consumption/Check.cs index 1673a5b..6ba94fc 100644 --- a/tests/package-consumption/Check.cs +++ b/tests/package-consumption/Check.cs @@ -108,8 +108,7 @@ public static void Throws(String label, String expectedMessageFragme Fail(label, $"expected {typeof(TException).Name}, but nothing was thrown"); } - private static void Pass(String label) => - Console.WriteLine($" PASS {label}"); + private static void Pass(String label) => Console.WriteLine($" PASS {label}"); private static void Fail(String label, String detail) { @@ -125,6 +124,6 @@ private static String Render(Object? value) => null => "null", Byte[] bytes => Convert.ToHexString(bytes), IFormattable formattable => formattable.ToString(null, CultureInfo.InvariantCulture), - _ => value.ToString() ?? String.Empty + _ => value.ToString() ?? String.Empty, }; } From 353c8c3df6a9681fbeebcbb58415a075617b02e0 Mon Sep 17 00:00:00 2001 From: David Liebeherr Date: Thu, 27 Aug 2026 06:57:23 +0200 Subject: [PATCH 06/12] build: enforce StyleCop member ordering, and apply it with ReSharper NewStyleCop.Analyzers reports a wrong order; it cannot fix one, because its ElementOrderCodeFixProvider is [NoCodeFix] and never registered. ReSharper does the fixing, through the file layout in DbConnectionPlus.slnx.DotSettings and a cleanup profile that reorders members and nothing else. So the order is defined twice and the two have to stay in step: stylecop.json is what is checked, the .DotSettings layout is what is applied. Every StyleCop category is switched off in .editorconfig and only the ordering rules plus SA1309 switched back on, so adding a StyleCop rule here is deliberate. Part of #21 Co-Authored-By: Claude Opus 5 --- .config/dotnet-tools.json | 7 + .editorconfig | 22 +++- DbConnectionPlus.sln.DotSettings | 27 ---- DbConnectionPlus.slnx.DotSettings | 210 ++++++++++++++++++++++++++++++ Directory.Build.props | 27 ++++ stylecop.json | 10 ++ 6 files changed, 274 insertions(+), 29 deletions(-) delete mode 100644 DbConnectionPlus.sln.DotSettings create mode 100644 DbConnectionPlus.slnx.DotSettings create mode 100644 stylecop.json diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 76f6a45..bfcc8ba 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,6 +15,13 @@ "csharpier" ], "rollForward": false + }, + "jetbrains.resharper.globaltools": { + "version": "2026.2.1", + "commands": [ + "jb" + ], + "rollForward": false } } } \ No newline at end of file diff --git a/.editorconfig b/.editorconfig index 8d003ae..1eeab81 100644 --- a/.editorconfig +++ b/.editorconfig @@ -229,8 +229,26 @@ dotnet_analyzer_diagnostic.category-StyleCop.CSharp.SpecialRules.severity = none # SA1201: Elements should appear in the correct order (by kind). dotnet_diagnostic.SA1201.severity = error -# SA1202: Elements should be ordered by access. -dotnet_diagnostic.SA1202.severity = error +# SA1202: Elements should be ordered by access. OFF, and this is the one place where the checker and the +# fixer genuinely disagree. +# +# The two tools classify an explicit interface implementation differently. StyleCop counts +# `void IFreezable.Freeze()` as public; ReSharper sorts it with the private members, because in C# it +# carries no access modifier. So ReSharper puts it last inside its kind group and StyleCop then reports +# a public member sitting after a private one - on four members here, and on every explicit interface +# implementation anyone writes from now on. +# +# There is no setting that reconciles them. Sorting interface members first in the file layout does not +# do it (ReSharper sorts them last, not first) and it separates the Equals overloads, which trips Sonar's +# S4136. That leaves a rule the fixer cannot satisfy: scripts/tidy-cs.ps1 would produce code the build +# rejects, and the next run would produce the same code again. A rule nothing can fix is worse than no +# rule, so it is off. +# +# What is lost: accessibility order is still APPLIED - the file layout in the .DotSettings sorts by access +# before anything else - it is just not VERIFIED by the build. Kind order (SA1201), constants (SA1203), +# static (SA1204) and readonly (SA1214) are all still checked, and all four keep accessibility as their +# higher-priority trait, so they only pass if the accessibility order is right anyway. +dotnet_diagnostic.SA1202.severity = none # SA1203: Constants should appear before fields. dotnet_diagnostic.SA1203.severity = error diff --git a/DbConnectionPlus.sln.DotSettings b/DbConnectionPlus.sln.DotSettings deleted file mode 100644 index 763f22a..0000000 --- a/DbConnectionPlus.sln.DotSettings +++ /dev/null @@ -1,27 +0,0 @@ - - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True - True \ No newline at end of file diff --git a/DbConnectionPlus.slnx.DotSettings b/DbConnectionPlus.slnx.DotSettings new file mode 100644 index 0000000..ac70d55 --- /dev/null +++ b/DbConnectionPlus.slnx.DotSettings @@ -0,0 +1,210 @@ + + <?xml version="1.0" encoding="utf-16"?> +<Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"> + <TypePattern DisplayName="Types marked [NoReorder]" Priority="100"> + <TypePattern.Match> + <HasAttribute Name="JetBrains.Annotations.NoReorderAttribute" /> + </TypePattern.Match> + </TypePattern> + <TypePattern DisplayName="StyleCop order" RemoveRegions="None"> + <Entry DisplayName="Constants"> + <Entry.Match> + <Kind Is="Constant" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Fields"> + <Entry.Match> + <Kind Is="Field" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Constructors"> + <Entry.Match> + <Kind Is="Constructor" /> + </Entry.Match> + <Entry.SortBy> + <Static /> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Finalizers"> + <Entry.Match> + <Kind Is="Destructor" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Delegates"> + <Entry.Match> + <Kind Is="Delegate" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Events"> + <Entry.Match> + <Kind Is="Event" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Enums"> + <Entry.Match> + <Kind Is="Enum" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Interfaces"> + <Entry.Match> + <Kind Is="Interface" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Properties"> + <Entry.Match> + <Kind Is="Property" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Indexers"> + <Entry.Match> + <Kind Is="Indexer" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Conversion operators"> + <Entry.Match> + <And> + <Kind Is="Operator" /> + <Or> + <Name Is="op_Implicit" /> + <Name Is="op_Explicit" /> + </Or> + </And> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Operators"> + <Entry.Match> + <Kind Is="Operator" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Methods"> + <Entry.Match> + <Kind Is="Method" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Structs"> + <Entry.Match> + <Kind Is="Struct" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Classes"> + <Entry.Match> + <Kind Is="Class" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + </TypePattern> +</Patterns> + <?xml version="1.0" encoding="utf-16"?><Profile name="ReorderMembers"><CSReorderTypeMembers>True</CSReorderTypeMembers></Profile> + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props index 5c74f7c..36ad4a1 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -40,6 +40,14 @@ --> True true + + + $(NoWarn);SA0001 @@ -55,10 +63,29 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + all runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + diff --git a/stylecop.json b/stylecop.json new file mode 100644 index 0000000..fea9d81 --- /dev/null +++ b/stylecop.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", + "settings": { + "orderingRules": { + "elementOrder": ["kind", "accessibility", "constant", "static", "readonly"], + "systemUsingDirectivesFirst": true, + "usingDirectivesPlacement": "outsideNamespace" + } + } +} From 48c97d6088a601ee461bf0546150f4672b47f471 Mon Sep 17 00:00:00 2001 From: David Liebeherr Date: Sun, 23 Aug 2026 04:17:01 +0200 Subject: [PATCH 07/12] style: reorder type members into StyleCop order Mechanical. Applied with: dotnet jb cleanupcode DbConnectionPlus.slnx --profile=ReorderMembers dotnet csharpier format . 133 files. Members now follow SA1201's order - fields, constructors, finalizers, delegates, events, enums, interfaces, properties, indexers, conversions, operators, methods, nested types - with constants ahead of fields, public ahead of private, static ahead of instance, readonly ahead of mutable, and alphabetical inside each group. The visible change is that fields move to the top of the type. This codebase kept them at the bottom; StyleCop puts them first. CSharpier runs after the reorder, because moving a member re-indents it and ReSharper indents to its own settings rather than CSharpier's. That is the order scripts/tidy-cs.ps1 uses too. On the one real risk - reordering fields changes the order their initializers run in, which can change behaviour. It does not here: a scan of every field initializer in the repository finds none that reads another field of the same type, so no initializer depends on the order. The full suite is green as well: 11005 passed, 0 failed, integration tests against all five databases included. This commit is listed in .git-blame-ignore-revs. Part of #21 Co-Authored-By: Claude Opus 5 --- .../AotJobFilter.cs | 20 +- .../Benchmarks.DeleteEntities.cs | 66 +- .../Benchmarks.DeleteEntity.cs | 52 +- .../Benchmarks.ExecuteNonQuery.cs | 36 +- .../Benchmarks.ExecuteReader.cs | 20 +- .../Benchmarks.ExecuteScalar.cs | 20 +- .../Benchmarks.Exists.cs | 12 +- .../Benchmarks.InsertEntities.cs | 124 +- .../Benchmarks.InsertEntity.cs | 30 +- .../Benchmarks.Parameter.cs | 12 +- .../Benchmarks.Query_Dynamic.cs | 22 +- .../Benchmarks.Query_Entities.cs | 42 +- .../Benchmarks.Query_Scalars.cs | 22 +- .../Benchmarks.Query_ValueTuples.cs | 38 +- ...enchmarks.TemporaryTable_ComplexObjects.cs | 152 +- .../Benchmarks.TemporaryTable_ScalarValues.cs | 44 +- .../Benchmarks.UpdateEntities.cs | 84 +- .../Benchmarks.UpdateEntity.cs | 74 +- .../DbConnectionPlus.Benchmarks/Benchmarks.cs | 92 +- .../BenchmarksConfig.cs | 9 +- .../BenchmarksOrderer.cs | 14 +- .../TestData/BenchmarkEntity.cs | 2 +- .../TestData/Generate.cs | 106 +- .../MySqlDatabaseAdapter.cs | 46 +- .../MySqlEntityManipulator.cs | 159 +- .../MySqlTemporaryTableBuilder.cs | 162 +- .../OracleDatabaseAdapter.cs | 148 +- .../OracleEntityManipulator.cs | 72 +- .../OracleTemporaryTableBuilder.cs | 300 ++-- .../PostgreSqlDatabaseAdapter.cs | 86 +- .../PostgreSqlEntityManipulator.cs | 160 +- .../PostgreSqlTemporaryTableBuilder.cs | 140 +- .../SqlServerDatabaseAdapter.cs | 50 +- .../SqlServerEntityManipulator.cs | 160 +- .../SqlServerTemporaryTableBuilder.cs | 266 ++-- .../SqliteDatabaseAdapter.cs | 48 +- .../SqliteEntityManipulator.cs | 160 +- .../SqliteTemporaryTableBuilder.cs | 162 +- .../DbConnectionPlusConfiguration.cs | 38 +- .../Configuration/EntityPropertyBuilder.cs | 76 +- .../Configuration/EntityTypeBuilder.cs | 70 +- .../Converters/ValueConverter.cs | 432 +++--- .../TemporaryTableDisposer.cs | 10 +- .../DbCommands/DbCommandDisposer.cs | 12 +- .../DbConnectionExtensions.Configuration.cs | 4 +- .../DbConnectionExtensions.Parameter.cs | 10 +- src/DbConnectionPlus/Dynamic/DataRow.cs | 42 +- src/DbConnectionPlus/Entities/EntityHelper.cs | 94 +- .../Extensions/Int32Extensions.cs | 4 +- .../Extensions/ObjectExtensions.cs | 32 +- .../Extensions/TypeExtensions.cs | 76 +- .../EntityMaterializerFactory.cs | 876 +++++------ .../MaterializerFactoryHelper.cs | 200 +-- .../ValueTupleMaterializerFactory.cs | 534 +++---- .../CommandDisposingDataReaderDecorator.cs | 20 +- .../Readers/EnumerableReader.cs | 423 ++--- .../SqlStatements/InterpolatedSqlStatement.cs | 236 +-- .../EntityManipulator.DeleteEntitiesTests.cs | 4 +- .../EntityManipulator.DeleteEntityTests.cs | 4 +- .../EntityManipulator.InsertEntitiesTests.cs | 4 +- .../EntityManipulator.InsertEntityTests.cs | 4 +- .../EntityManipulator.UpdateEntitiesTests.cs | 4 +- .../EntityManipulator.UpdateEntityTests.cs | 4 +- .../Oracle/OracleDatabaseAdapterTests.cs | 4 +- .../PostgreSqlDatabaseAdapterTests.cs | 4 +- .../SqlServerDatabaseAdapterTests.cs | 4 +- .../TemporaryTableBuilderTests.cs | 62 +- .../DbCommands/DbCommandDisposerTests.cs | 62 +- ...onnectionExtensions.TemporaryTableTests.cs | 168 +- .../IntegrationTestsBase.cs | 116 +- ...ommandDisposingDataReaderDecoratorTests.cs | 32 +- .../Containers/MySqlContainerFixture.cs | 8 +- .../Containers/OracleContainerFixture.cs | 38 +- .../Containers/PostgreSqlContainerFixture.cs | 4 +- .../Containers/SqlServerContainerFixture.cs | 4 +- .../Containers/TestDatabaseContainer.cs | 18 +- .../Containers/TestDatabaseContainers.cs | 16 +- .../TestDatabase/ITestDatabaseProvider.cs | 22 +- .../TestDatabase/MySqlTestDatabaseProvider.cs | 262 ++-- .../OracleTestDatabaseProvider.cs | 222 +-- .../PostgreSqlTestDatabaseProvider.cs | 222 +-- .../SQLiteTestDatabaseProvider.cs | 140 +- .../SqlServerTestDatabaseProvider.cs | 264 ++-- .../Assertions/DecoratorAssertions.cs | 18 +- .../Configuration/EntityTypeBuilderTests.cs | 44 +- .../Converters/EnumConverterTests.cs | 214 +-- .../Converters/ValueConverterTests.cs | 1374 ++++++++--------- .../EntityManipulatorTests.cs | 18 +- .../MySql/MySqlDatabaseAdapterTests.cs | 4 +- .../MySql/MySqlTemporaryTableBuilderTests.cs | 26 +- .../Oracle/OracleDatabaseAdapterTests.cs | 4 +- .../OracleTemporaryTableBuilderTests.cs | 48 +- .../PostgreSqlDatabaseAdapterTests.cs | 4 +- .../PostgreSqlTemporaryTableBuilderTests.cs | 26 +- .../SqlServerDatabaseAdapterTests.cs | 4 +- .../SqlServerTemporaryTableBuilderTests.cs | 26 +- .../Sqlite/SqliteDatabaseAdapterTests.cs | 4 +- .../SqliteTemporaryTableBuilderTests.cs | 26 +- .../TemporaryTableDisposerTests.cs | 34 +- .../DbCommands/DbCommandBuilderTests.cs | 6 +- .../DbCommands/DbCommandDisposerTests.cs | 52 +- ...onnectionExtensions.DeleteEntitiesTests.cs | 26 +- ...bConnectionExtensions.DeleteEntityTests.cs | 30 +- ...onnectionExtensions.InsertEntitiesTests.cs | 26 +- ...bConnectionExtensions.InsertEntityTests.cs | 30 +- .../DbConnectionExtensions.ParameterTests.cs | 4 +- ...onnectionExtensions.TemporaryTableTests.cs | 4 +- ...onnectionExtensions.UpdateEntitiesTests.cs | 26 +- ...bConnectionExtensions.UpdateEntityTests.cs | 30 +- .../Dynamic/DataRowTests.cs | 124 +- .../Entities/EntityHelperTests.cs | 142 +- .../Extensions/ObjectExtensionsTests.cs | 46 +- .../EntityMaterializerFactoryTests.cs | 472 +++--- .../ValueTupleMaterializerFactoryTests.cs | 418 ++--- .../Mocks/MockDbParameterCollection.cs | 4 +- ...ommandDisposingDataReaderDecoratorTests.cs | 40 +- .../Readers/EnumerableReaderOptionsTests.cs | 32 +- .../Readers/EnumerableReaderTests.cs | 137 +- .../StatementMethodTestsBase.cs | 38 +- .../TestData/Entity.cs | 2 +- .../EntityWithDifferentCasingProperties.cs | 2 +- .../TestData/FakeConnectionA.cs | 10 +- .../TestData/FakeConnectionB.cs | 10 +- .../TestData/FakeConnectionC.cs | 10 +- .../TestData/Generate.cs | 22 +- .../TestData/NotAValueTuple.cs | 4 +- .../Trimming/ILLinkDescriptorsTests.cs | 4 +- 127 files changed, 5862 insertions(+), 5860 deletions(-) diff --git a/benchmarks/DbConnectionPlus.Benchmarks/AotJobFilter.cs b/benchmarks/DbConnectionPlus.Benchmarks/AotJobFilter.cs index c834e62..cf9747f 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/AotJobFilter.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/AotJobFilter.cs @@ -13,14 +13,8 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; // file for the measurements behind that. public class AotJobFilter : IFilter { - public bool Predicate(BenchmarkCase benchmarkCase) - { - var isAotJob = benchmarkCase.Job.Id.Contains(BenchmarksConfig.AotJobId, StringComparison.Ordinal); - var benchmarkName = benchmarkCase.Descriptor.WorkloadMethod.Name; - var isAotOnlyBenchmark = benchmarkName.EndsWith(AotOnlyBenchmarkSuffix, StringComparison.Ordinal); - - return isAotJob ? AotJobBenchmarks.Contains(benchmarkName) : !isAotOnlyBenchmark; - } + // Marks a benchmark as Native AOT only, so that it is kept out of the JIT job. + private const string AotOnlyBenchmarkSuffix = "_Aot"; // TemporaryTable_ComplexObjects is here because it ends in a Query over the temporary // table: its write path is single path, its read path is not. @@ -40,6 +34,12 @@ public bool Predicate(BenchmarkCase benchmarkCase) nameof(Benchmarks.TemporaryTable_ComplexObjects_DbConnectionPlus), ]; - // Marks a benchmark as Native AOT only, so that it is kept out of the JIT job. - private const string AotOnlyBenchmarkSuffix = "_Aot"; + public bool Predicate(BenchmarkCase benchmarkCase) + { + var isAotJob = benchmarkCase.Job.Id.Contains(BenchmarksConfig.AotJobId, StringComparison.Ordinal); + var benchmarkName = benchmarkCase.Descriptor.WorkloadMethod.Name; + var isAotOnlyBenchmark = benchmarkName.EndsWith(AotOnlyBenchmarkSuffix, StringComparison.Ordinal); + + return isAotJob ? AotJobBenchmarks.Contains(benchmarkName) : !isAotOnlyBenchmark; + } } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntities.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntities.cs index 220f978..8542d41 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntities.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntities.cs @@ -7,30 +7,19 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { - [GlobalCleanup( - Targets = [ - nameof(DeleteEntities_Command), - nameof(DeleteEntities_Dapper), - nameof(DeleteEntities_DbConnectionPlus), - ] - )] - public void DeleteEntities__Cleanup() => this.connection.Dispose(); + private const string DeleteEntities_Category = "DeleteEntities"; + private const int DeleteEntities_EntitiesPerOperation = 250; - [GlobalSetup( - Targets = [ - nameof(DeleteEntities_Command), - nameof(DeleteEntities_Dapper), - nameof(DeleteEntities_DbConnectionPlus), - ] - )] - public void DeleteEntities__Setup() - { - this.SetupDatabase(DeleteEntities_EntitiesPerOperation * DeleteEntities_OperationsPerInvoke); + // Batches per invocation: one reported operation is one delete call over + // DeleteEntities_EntitiesPerOperation entities. + // + // The transaction is rolled back rather than committed, so every invocation puts the rows back. See + // DeleteEntity_OperationsPerInvoke for why that matters and for the measurement showing a rollback costs + // what a commit costs. Twenty batches is 5 000 seeded rows, down from 75 000, and it amortizes the + // transaction far past the point where it could affect the ratios. + private const int DeleteEntities_OperationsPerInvoke = 20; - // The batches are built once here so that the benchmarks do not slice the entity list inside the measured - // region. The slicing was identical for all three implementations and therefore only compressed the ratios. - this.deleteEntities_batches = [.. this.entitiesInDb.Chunk(DeleteEntities_EntitiesPerOperation)]; - } + private List deleteEntities_batches = null!; [Benchmark(Baseline = true, OperationsPerInvoke = DeleteEntities_OperationsPerInvoke)] [BenchmarkCategory(DeleteEntities_Category)] @@ -90,17 +79,28 @@ public void DeleteEntities_DbConnectionPlus() transaction.Rollback(); } - private List deleteEntities_batches = null!; + [GlobalCleanup( + Targets = [ + nameof(DeleteEntities_Command), + nameof(DeleteEntities_Dapper), + nameof(DeleteEntities_DbConnectionPlus), + ] + )] + public void DeleteEntities__Cleanup() => this.connection.Dispose(); - private const string DeleteEntities_Category = "DeleteEntities"; - private const int DeleteEntities_EntitiesPerOperation = 250; + [GlobalSetup( + Targets = [ + nameof(DeleteEntities_Command), + nameof(DeleteEntities_Dapper), + nameof(DeleteEntities_DbConnectionPlus), + ] + )] + public void DeleteEntities__Setup() + { + this.SetupDatabase(DeleteEntities_EntitiesPerOperation * DeleteEntities_OperationsPerInvoke); - // Batches per invocation: one reported operation is one delete call over - // DeleteEntities_EntitiesPerOperation entities. - // - // The transaction is rolled back rather than committed, so every invocation puts the rows back. See - // DeleteEntity_OperationsPerInvoke for why that matters and for the measurement showing a rollback costs - // what a commit costs. Twenty batches is 5 000 seeded rows, down from 75 000, and it amortizes the - // transaction far past the point where it could affect the ratios. - private const int DeleteEntities_OperationsPerInvoke = 20; + // The batches are built once here so that the benchmarks do not slice the entity list inside the measured + // region. The slicing was identical for all three implementations and therefore only compressed the ratios. + this.deleteEntities_batches = [.. this.entitiesInDb.Chunk(DeleteEntities_EntitiesPerOperation)]; + } } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntity.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntity.cs index 3b33f48..1b6751c 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntity.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.DeleteEntity.cs @@ -7,15 +7,25 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { - [GlobalCleanup( - Targets = [nameof(DeleteEntity_Command), nameof(DeleteEntity_Dapper), nameof(DeleteEntity_DbConnectionPlus)] - )] - public void DeleteEntity__Cleanup() => this.connection.Dispose(); + private const string DeleteEntity_Category = "DeleteEntity"; - [GlobalSetup( - Targets = [nameof(DeleteEntity_Command), nameof(DeleteEntity_Dapper), nameof(DeleteEntity_DbConnectionPlus)] - )] - public void DeleteEntity__Setup() => this.SetupDatabase(DeleteEntity_OperationsPerInvoke); + // Deletes per invocation, and also the number of rows seeded into the table. + // + // The transaction is rolled back rather than committed, so every invocation puts the rows back and the next + // one deletes them again. That is what lets this category drop [IterationSetup], and dropping it is the + // point: an iteration setup pins InvocationCount to 1, which makes the iteration time a function of this + // constant and of how fast the machine is - and BenchmarkDotNet then warns that the iteration is too short + // to measure reliably. Without it the pilot stage tunes the invocation count by itself, on any machine. + // + // Rolling back costs the same as committing: measured on this schema in an in-memory SQLite database at 1, + // 100, 1 000, 10 000 and 40 000 rows, the rollback/commit ratio stayed between 0.98x and 1.03x with no + // trend - and it is identical for all three implementations either way. + // + // It is 1 000 rather than 1 because BeginTransaction plus Rollback costs roughly 3 us against roughly + // 0.5 us for the marginal delete. At one delete per invocation that fixed cost would be about two thirds + // of the measurement - not a bias, since all three implementations pay it, but it would compress the + // ratios this benchmark exists to show. Amortized over 1 000 deletes it is well under 1 %. + private const int DeleteEntity_OperationsPerInvoke = 1000; [Benchmark(Baseline = true, OperationsPerInvoke = DeleteEntity_OperationsPerInvoke)] [BenchmarkCategory(DeleteEntity_Category)] @@ -71,23 +81,13 @@ public void DeleteEntity_DbConnectionPlus() transaction.Rollback(); } - private const string DeleteEntity_Category = "DeleteEntity"; + [GlobalCleanup( + Targets = [nameof(DeleteEntity_Command), nameof(DeleteEntity_Dapper), nameof(DeleteEntity_DbConnectionPlus)] + )] + public void DeleteEntity__Cleanup() => this.connection.Dispose(); - // Deletes per invocation, and also the number of rows seeded into the table. - // - // The transaction is rolled back rather than committed, so every invocation puts the rows back and the next - // one deletes them again. That is what lets this category drop [IterationSetup], and dropping it is the - // point: an iteration setup pins InvocationCount to 1, which makes the iteration time a function of this - // constant and of how fast the machine is - and BenchmarkDotNet then warns that the iteration is too short - // to measure reliably. Without it the pilot stage tunes the invocation count by itself, on any machine. - // - // Rolling back costs the same as committing: measured on this schema in an in-memory SQLite database at 1, - // 100, 1 000, 10 000 and 40 000 rows, the rollback/commit ratio stayed between 0.98x and 1.03x with no - // trend - and it is identical for all three implementations either way. - // - // It is 1 000 rather than 1 because BeginTransaction plus Rollback costs roughly 3 us against roughly - // 0.5 us for the marginal delete. At one delete per invocation that fixed cost would be about two thirds - // of the measurement - not a bias, since all three implementations pay it, but it would compress the - // ratios this benchmark exists to show. Amortized over 1 000 deletes it is well under 1 %. - private const int DeleteEntity_OperationsPerInvoke = 1000; + [GlobalSetup( + Targets = [nameof(DeleteEntity_Command), nameof(DeleteEntity_Dapper), nameof(DeleteEntity_DbConnectionPlus)] + )] + public void DeleteEntity__Setup() => this.SetupDatabase(DeleteEntity_OperationsPerInvoke); } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteNonQuery.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteNonQuery.cs index e3d3498..6306468 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteNonQuery.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteNonQuery.cs @@ -7,23 +7,7 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { - [GlobalCleanup( - Targets = [ - nameof(ExecuteNonQuery_Command), - nameof(ExecuteNonQuery_Dapper), - nameof(ExecuteNonQuery_DbConnectionPlus), - ] - )] - public void ExecuteNonQuery__Cleanup() => this.connection.Dispose(); - - [GlobalSetup( - Targets = [ - nameof(ExecuteNonQuery_Command), - nameof(ExecuteNonQuery_Dapper), - nameof(ExecuteNonQuery_DbConnectionPlus), - ] - )] - public void ExecuteNonQuery__Setup() => this.SetupDatabase(0); + private const string ExecuteNonQuery_Category = "ExecuteNonQuery"; [Benchmark(Baseline = true)] [BenchmarkCategory(ExecuteNonQuery_Category)] @@ -53,5 +37,21 @@ public void ExecuteNonQuery_Dapper() => public void ExecuteNonQuery_DbConnectionPlus() => this.connection.ExecuteNonQuery($"DELETE FROM Entity WHERE Id = {Parameter(-1)}"); - private const string ExecuteNonQuery_Category = "ExecuteNonQuery"; + [GlobalCleanup( + Targets = [ + nameof(ExecuteNonQuery_Command), + nameof(ExecuteNonQuery_Dapper), + nameof(ExecuteNonQuery_DbConnectionPlus), + ] + )] + public void ExecuteNonQuery__Cleanup() => this.connection.Dispose(); + + [GlobalSetup( + Targets = [ + nameof(ExecuteNonQuery_Command), + nameof(ExecuteNonQuery_Dapper), + nameof(ExecuteNonQuery_DbConnectionPlus), + ] + )] + public void ExecuteNonQuery__Setup() => this.SetupDatabase(0); } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteReader.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteReader.cs index 4553d13..e4b3c44 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteReader.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteReader.cs @@ -7,15 +7,7 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { - [GlobalCleanup( - Targets = [nameof(ExecuteReader_Command), nameof(ExecuteReader_Dapper), nameof(ExecuteReader_DbConnectionPlus)] - )] - public void ExecuteReader__Cleanup() => this.connection.Dispose(); - - [GlobalSetup( - Targets = [nameof(ExecuteReader_Command), nameof(ExecuteReader_Dapper), nameof(ExecuteReader_DbConnectionPlus)] - )] - public void ExecuteReader__Setup() => this.SetupDatabase(100); + private const string ExecuteReader_Category = "ExecuteReader"; [Benchmark(Baseline = true)] [BenchmarkCategory(ExecuteReader_Category)] @@ -69,5 +61,13 @@ public List ExecuteReader_DbConnectionPlus() return result; } - private const string ExecuteReader_Category = "ExecuteReader"; + [GlobalCleanup( + Targets = [nameof(ExecuteReader_Command), nameof(ExecuteReader_Dapper), nameof(ExecuteReader_DbConnectionPlus)] + )] + public void ExecuteReader__Cleanup() => this.connection.Dispose(); + + [GlobalSetup( + Targets = [nameof(ExecuteReader_Command), nameof(ExecuteReader_Dapper), nameof(ExecuteReader_DbConnectionPlus)] + )] + public void ExecuteReader__Setup() => this.SetupDatabase(100); } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteScalar.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteScalar.cs index a4cde04..84e9261 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteScalar.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.ExecuteScalar.cs @@ -7,15 +7,7 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { - [GlobalCleanup( - Targets = [nameof(ExecuteScalar_Command), nameof(ExecuteScalar_Dapper), nameof(ExecuteScalar_DbConnectionPlus)] - )] - public void ExecuteScalar__Cleanup() => this.connection.Dispose(); - - [GlobalSetup( - Targets = [nameof(ExecuteScalar_Command), nameof(ExecuteScalar_Dapper), nameof(ExecuteScalar_DbConnectionPlus)] - )] - public void ExecuteScalar__Setup() => this.SetupDatabase(1); + private const string ExecuteScalar_Category = "ExecuteScalar"; [Benchmark(Baseline = true)] [BenchmarkCategory(ExecuteScalar_Category)] @@ -60,5 +52,13 @@ public string ExecuteScalar_DbConnectionPlus() ); } - private const string ExecuteScalar_Category = "ExecuteScalar"; + [GlobalCleanup( + Targets = [nameof(ExecuteScalar_Command), nameof(ExecuteScalar_Dapper), nameof(ExecuteScalar_DbConnectionPlus)] + )] + public void ExecuteScalar__Cleanup() => this.connection.Dispose(); + + [GlobalSetup( + Targets = [nameof(ExecuteScalar_Command), nameof(ExecuteScalar_Dapper), nameof(ExecuteScalar_DbConnectionPlus)] + )] + public void ExecuteScalar__Setup() => this.SetupDatabase(1); } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Exists.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Exists.cs index cc03580..064d0fe 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Exists.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Exists.cs @@ -7,11 +7,7 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { - [GlobalCleanup(Targets = [nameof(Exists_Command), nameof(Exists_Dapper), nameof(Exists_DbConnectionPlus)])] - public void Exists__Cleanup() => this.connection.Dispose(); - - [GlobalSetup(Targets = [nameof(Exists_Command), nameof(Exists_Dapper), nameof(Exists_DbConnectionPlus)])] - public void Exists__Setup() => this.SetupDatabase(1); + private const string Exists_Category = "Exists"; [Benchmark(Baseline = true)] [BenchmarkCategory(Exists_Category)] @@ -57,5 +53,9 @@ public bool Exists_DbConnectionPlus() return this.connection.Exists($"SELECT 1 FROM Entity WHERE Id = {Parameter(entityId)}"); } - private const string Exists_Category = "Exists"; + [GlobalCleanup(Targets = [nameof(Exists_Command), nameof(Exists_Dapper), nameof(Exists_DbConnectionPlus)])] + public void Exists__Cleanup() => this.connection.Dispose(); + + [GlobalSetup(Targets = [nameof(Exists_Command), nameof(Exists_Dapper), nameof(Exists_DbConnectionPlus)])] + public void Exists__Setup() => this.SetupDatabase(1); } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntities.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntities.cs index 872bf23..2c4d7f3 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntities.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntities.cs @@ -7,23 +7,51 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { - [GlobalCleanup( - Targets = [ - nameof(InsertEntities_Command), - nameof(InsertEntities_Dapper), - nameof(InsertEntities_DbConnectionPlus), - ] - )] - public void InsertEntities__Cleanup() => this.connection.Dispose(); + private const string InsertEntities_Category = "InsertEntities"; + private const int InsertEntities_EntitiesPerOperation = 200; - [GlobalSetup( - Targets = [ - nameof(InsertEntities_Command), - nameof(InsertEntities_Dapper), - nameof(InsertEntities_DbConnectionPlus), - ] - )] - public void InsertEntities__Setup() => this.SetupDatabase(0); + private const string InsertEntitySql = """ + INSERT INTO Entity + ( + Id, + BooleanValue, + BytesValue, + ByteValue, + CharValue, + DateTimeValue, + DecimalValue, + DoubleValue, + EnumValue, + Int16Value, + Int32Value, + Int64Value, + SingleValue, + StringValue + ) + VALUES + ( + @Id, + @BooleanValue, + @BytesValue, + @ByteValue, + @CharValue, + @DateTimeValue, + @DecimalValue, + @DoubleValue, + @EnumValue, + @Int16Value, + @Int32Value, + @Int64Value, + @SingleValue, + @StringValue + ) + """; + + private readonly List insertEntities_entitiesToInsert = Generate.Multiple( + InsertEntities_EntitiesPerOperation + ); + + private long insertEntities_nextId; [Benchmark(Baseline = true)] [BenchmarkCategory(InsertEntities_Category)] @@ -81,6 +109,24 @@ public void InsertEntities_DbConnectionPlus() this.connection.InsertEntities(this.insertEntities_entitiesToInsert); } + [GlobalCleanup( + Targets = [ + nameof(InsertEntities_Command), + nameof(InsertEntities_Dapper), + nameof(InsertEntities_DbConnectionPlus), + ] + )] + public void InsertEntities__Cleanup() => this.connection.Dispose(); + + [GlobalSetup( + Targets = [ + nameof(InsertEntities_Command), + nameof(InsertEntities_Dapper), + nameof(InsertEntities_DbConnectionPlus), + ] + )] + public void InsertEntities__Setup() => this.SetupDatabase(0); + // A fresh key per entity, because Id is the primary key and the benchmarks insert the same set of entities // over and over into a table that starts out empty. This runs inside the measured region, but it is a few // hundred nanoseconds of field writes against an operation of several milliseconds, and all three @@ -92,50 +138,4 @@ private void AssignNextInsertEntitiesIds() entity.Id = ++this.insertEntities_nextId; } } - - private readonly List insertEntities_entitiesToInsert = Generate.Multiple( - InsertEntities_EntitiesPerOperation - ); - - private long insertEntities_nextId; - - private const string InsertEntities_Category = "InsertEntities"; - private const int InsertEntities_EntitiesPerOperation = 200; - - private const string InsertEntitySql = """ - INSERT INTO Entity - ( - Id, - BooleanValue, - BytesValue, - ByteValue, - CharValue, - DateTimeValue, - DecimalValue, - DoubleValue, - EnumValue, - Int16Value, - Int32Value, - Int64Value, - SingleValue, - StringValue - ) - VALUES - ( - @Id, - @BooleanValue, - @BytesValue, - @ByteValue, - @CharValue, - @DateTimeValue, - @DecimalValue, - @DoubleValue, - @EnumValue, - @Int16Value, - @Int32Value, - @Int64Value, - @SingleValue, - @StringValue - ) - """; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntity.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntity.cs index 3a3fb0a..857169a 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntity.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.InsertEntity.cs @@ -7,15 +7,13 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { - [GlobalCleanup( - Targets = [nameof(InsertEntity_Command), nameof(InsertEntity_Dapper), nameof(InsertEntity_DbConnectionPlus)] - )] - public void InsertEntity__Cleanup() => this.connection.Dispose(); + private const string InsertEntity_Category = "InsertEntity"; - [GlobalSetup( - Targets = [nameof(InsertEntity_Command), nameof(InsertEntity_Dapper), nameof(InsertEntity_DbConnectionPlus)] - )] - public void InsertEntity__Setup() => this.SetupDatabase(0); + private readonly BenchmarkEntity insertEntity_entityToInsert = Generate.Single(); + + // A fresh key per invocation, because Id is the primary key and the benchmarks insert the same entity over + // and over into a table that starts out empty. + private long insertEntity_nextId; [Benchmark(Baseline = true)] [BenchmarkCategory(InsertEntity_Category)] @@ -70,13 +68,15 @@ public void InsertEntity_DbConnectionPlus() this.connection.InsertEntity(this.insertEntity_entityToInsert); } - private void AssignNextInsertEntityId() => this.insertEntity_entityToInsert.Id = ++this.insertEntity_nextId; - - private readonly BenchmarkEntity insertEntity_entityToInsert = Generate.Single(); + [GlobalCleanup( + Targets = [nameof(InsertEntity_Command), nameof(InsertEntity_Dapper), nameof(InsertEntity_DbConnectionPlus)] + )] + public void InsertEntity__Cleanup() => this.connection.Dispose(); - // A fresh key per invocation, because Id is the primary key and the benchmarks insert the same entity over - // and over into a table that starts out empty. - private long insertEntity_nextId; + [GlobalSetup( + Targets = [nameof(InsertEntity_Command), nameof(InsertEntity_Dapper), nameof(InsertEntity_DbConnectionPlus)] + )] + public void InsertEntity__Setup() => this.SetupDatabase(0); - private const string InsertEntity_Category = "InsertEntity"; + private void AssignNextInsertEntityId() => this.insertEntity_entityToInsert.Id = ++this.insertEntity_nextId; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Parameter.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Parameter.cs index 12d8391..6d23495 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Parameter.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Parameter.cs @@ -7,11 +7,7 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { - [GlobalCleanup(Targets = [nameof(Parameter_Command), nameof(Parameter_Dapper), nameof(Parameter_DbConnectionPlus)])] - public void Parameter__Cleanup() => this.connection.Dispose(); - - [GlobalSetup(Targets = [nameof(Parameter_Command), nameof(Parameter_Dapper), nameof(Parameter_DbConnectionPlus)])] - public void Parameter__Setup() => this.SetupDatabase(0); + private const string Parameter_Category = "Parameter"; [Benchmark(Baseline = true)] [BenchmarkCategory(Parameter_Category)] @@ -66,5 +62,9 @@ public long Parameter_DbConnectionPlus() => """ ); - private const string Parameter_Category = "Parameter"; + [GlobalCleanup(Targets = [nameof(Parameter_Command), nameof(Parameter_Dapper), nameof(Parameter_DbConnectionPlus)])] + public void Parameter__Cleanup() => this.connection.Dispose(); + + [GlobalSetup(Targets = [nameof(Parameter_Command), nameof(Parameter_Dapper), nameof(Parameter_DbConnectionPlus)])] + public void Parameter__Setup() => this.SetupDatabase(0); } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Dynamic.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Dynamic.cs index 9e67945..249e947 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Dynamic.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Dynamic.cs @@ -9,15 +9,8 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { - [GlobalCleanup( - Targets = [nameof(Query_Dynamic_Command), nameof(Query_Dynamic_Dapper), nameof(Query_Dynamic_DbConnectionPlus)] - )] - public void Query_Dynamic__Cleanup() => this.connection.Dispose(); - - [GlobalSetup( - Targets = [nameof(Query_Dynamic_Command), nameof(Query_Dynamic_Dapper), nameof(Query_Dynamic_DbConnectionPlus)] - )] - public void Query_Dynamic__Setup() => this.SetupDatabase(Query_Dynamic_EntitiesPerOperation); + private const string Query_Dynamic_Category = "Query_Dynamic"; + private const int Query_Dynamic_EntitiesPerOperation = 100; [Benchmark(Baseline = true)] [BenchmarkCategory(Query_Dynamic_Category)] @@ -68,6 +61,13 @@ public List Query_Dynamic_Command() [BenchmarkCategory(Query_Dynamic_Category)] public List Query_Dynamic_DbConnectionPlus() => [.. this.connection.Query("SELECT * FROM Entity")]; - private const string Query_Dynamic_Category = "Query_Dynamic"; - private const int Query_Dynamic_EntitiesPerOperation = 100; + [GlobalCleanup( + Targets = [nameof(Query_Dynamic_Command), nameof(Query_Dynamic_Dapper), nameof(Query_Dynamic_DbConnectionPlus)] + )] + public void Query_Dynamic__Cleanup() => this.connection.Dispose(); + + [GlobalSetup( + Targets = [nameof(Query_Dynamic_Command), nameof(Query_Dynamic_Dapper), nameof(Query_Dynamic_DbConnectionPlus)] + )] + public void Query_Dynamic__Setup() => this.SetupDatabase(Query_Dynamic_EntitiesPerOperation); } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Entities.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Entities.cs index ccae5cc..963968c 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Entities.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Entities.cs @@ -7,25 +7,8 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { - [GlobalCleanup( - Targets = [ - nameof(Query_Entities_Command), - nameof(Query_Entities_Dapper), - nameof(Query_Entities_Dapper_Aot), - nameof(Query_Entities_DbConnectionPlus), - ] - )] - public void Query_Entities__Cleanup() => this.connection.Dispose(); - - [GlobalSetup( - Targets = [ - nameof(Query_Entities_Command), - nameof(Query_Entities_Dapper), - nameof(Query_Entities_Dapper_Aot), - nameof(Query_Entities_DbConnectionPlus), - ] - )] - public void Query_Entities__Setup() => this.SetupDatabase(Query_Entities_EntitiesPerOperation); + private const string Query_Entities_Category = "Query_Entities"; + private const int Query_Entities_EntitiesPerOperation = 100; [Benchmark(Baseline = true)] [BenchmarkCategory(Query_Entities_Category)] @@ -67,6 +50,23 @@ public List Query_Entities_Dapper_Aot() => public List Query_Entities_DbConnectionPlus() => [.. this.connection.Query("SELECT * FROM Entity")]; - private const string Query_Entities_Category = "Query_Entities"; - private const int Query_Entities_EntitiesPerOperation = 100; + [GlobalCleanup( + Targets = [ + nameof(Query_Entities_Command), + nameof(Query_Entities_Dapper), + nameof(Query_Entities_Dapper_Aot), + nameof(Query_Entities_DbConnectionPlus), + ] + )] + public void Query_Entities__Cleanup() => this.connection.Dispose(); + + [GlobalSetup( + Targets = [ + nameof(Query_Entities_Command), + nameof(Query_Entities_Dapper), + nameof(Query_Entities_Dapper_Aot), + nameof(Query_Entities_DbConnectionPlus), + ] + )] + public void Query_Entities__Setup() => this.SetupDatabase(Query_Entities_EntitiesPerOperation); } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Scalars.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Scalars.cs index 5985eab..c3a12ce 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Scalars.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_Scalars.cs @@ -7,15 +7,8 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { - [GlobalCleanup( - Targets = [nameof(Query_Scalars_Command), nameof(Query_Scalars_Dapper), nameof(Query_Scalars_DbConnectionPlus)] - )] - public void Query_Scalars__Cleanup() => this.connection.Dispose(); - - [GlobalSetup( - Targets = [nameof(Query_Scalars_Command), nameof(Query_Scalars_Dapper), nameof(Query_Scalars_DbConnectionPlus)] - )] - public void Query_Scalars__Setup() => this.SetupDatabase(Query_Scalars_EntitiesPerOperation); + private const string Query_Scalars_Category = "Query_Scalars"; + private const int Query_Scalars_EntitiesPerOperation = 600; [Benchmark(Baseline = true)] [BenchmarkCategory(Query_Scalars_Category)] @@ -45,6 +38,13 @@ public List Query_Scalars_Command() [BenchmarkCategory(Query_Scalars_Category)] public List Query_Scalars_DbConnectionPlus() => [.. this.connection.Query("SELECT Id FROM Entity")]; - private const string Query_Scalars_Category = "Query_Scalars"; - private const int Query_Scalars_EntitiesPerOperation = 600; + [GlobalCleanup( + Targets = [nameof(Query_Scalars_Command), nameof(Query_Scalars_Dapper), nameof(Query_Scalars_DbConnectionPlus)] + )] + public void Query_Scalars__Cleanup() => this.connection.Dispose(); + + [GlobalSetup( + Targets = [nameof(Query_Scalars_Command), nameof(Query_Scalars_Dapper), nameof(Query_Scalars_DbConnectionPlus)] + )] + public void Query_Scalars__Setup() => this.SetupDatabase(Query_Scalars_EntitiesPerOperation); } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_ValueTuples.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_ValueTuples.cs index fe57da2..6c9f9af 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_ValueTuples.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.Query_ValueTuples.cs @@ -7,23 +7,8 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { - [GlobalCleanup( - Targets = [ - nameof(Query_ValueTuples_Command), - nameof(Query_ValueTuples_Dapper), - nameof(Query_ValueTuples_DbConnectionPlus), - ] - )] - public void Query_ValueTuples__Cleanup() => this.connection.Dispose(); - - [GlobalSetup( - Targets = [ - nameof(Query_ValueTuples_Command), - nameof(Query_ValueTuples_Dapper), - nameof(Query_ValueTuples_DbConnectionPlus), - ] - )] - public void Query_ValueTuples__Setup() => this.SetupDatabase(Query_ValueTuples_EntitiesPerOperation); + private const string Query_ValueTuples_Category = "Query_ValueTuples"; + private const int Query_ValueTuples_EntitiesPerOperation = 150; [Benchmark(Baseline = true)] [BenchmarkCategory(Query_ValueTuples_Category)] @@ -82,6 +67,21 @@ string StringValue ), ]; - private const string Query_ValueTuples_Category = "Query_ValueTuples"; - private const int Query_ValueTuples_EntitiesPerOperation = 150; + [GlobalCleanup( + Targets = [ + nameof(Query_ValueTuples_Command), + nameof(Query_ValueTuples_Dapper), + nameof(Query_ValueTuples_DbConnectionPlus), + ] + )] + public void Query_ValueTuples__Cleanup() => this.connection.Dispose(); + + [GlobalSetup( + Targets = [ + nameof(Query_ValueTuples_Command), + nameof(Query_ValueTuples_Dapper), + nameof(Query_ValueTuples_DbConnectionPlus), + ] + )] + public void Query_ValueTuples__Setup() => this.SetupDatabase(Query_ValueTuples_EntitiesPerOperation); } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ComplexObjects.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ComplexObjects.cs index 476cd0b..d1823aa 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ComplexObjects.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ComplexObjects.cs @@ -7,24 +7,66 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { - [GlobalCleanup( - Targets = [ - nameof(TemporaryTable_ComplexObjects_Command), - nameof(TemporaryTable_ComplexObjects_Dapper), - nameof(TemporaryTable_ComplexObjects_DbConnectionPlus), - ] - )] - public void TemporaryTable_ComplexObjects__Cleanup() => this.connection.Dispose(); + private const string CreateTempEntitiesTableSql = """ + CREATE TEMP TABLE Entities ( + Id INTEGER, + BooleanValue INTEGER, + BytesValue BLOB, + ByteValue INTEGER, + CharValue TEXT, + DateTimeValue TEXT, + DecimalValue TEXT, + DoubleValue REAL, + EnumValue TEXT, + Int16Value INTEGER, + Int32Value INTEGER, + Int64Value INTEGER, + SingleValue REAL, + StringValue TEXT + ) + """; - [GlobalSetup( - Targets = [ - nameof(TemporaryTable_ComplexObjects_Command), - nameof(TemporaryTable_ComplexObjects_Dapper), - nameof(TemporaryTable_ComplexObjects_DbConnectionPlus), - ] - )] - public void TemporaryTable_ComplexObjects__Setup() => - this.SetupDatabase(TemporaryTable_ComplexObjects_EntitiesPerOperation); + private const string InsertIntoTempEntities = """ + INSERT INTO temp.Entities ( + Id, + BooleanValue, + BytesValue, + ByteValue, + CharValue, + DateTimeValue, + DecimalValue, + DoubleValue, + EnumValue, + Int16Value, + Int32Value, + Int64Value, + SingleValue, + StringValue + ) + VALUES ( + @Id, + @BooleanValue, + @BytesValue, + @ByteValue, + @CharValue, + @DateTimeValue, + @DecimalValue, + @DoubleValue, + @EnumValue, + @Int16Value, + @Int32Value, + @Int64Value, + @SingleValue, + @StringValue + ) + """; + + private const string TemporaryTable_ComplexObjects_Category = "TemporaryTable_ComplexObjects"; + private const int TemporaryTable_ComplexObjects_EntitiesPerOperation = 250; + + private readonly List temporaryTable_ComplexObjects_Entities = Generate.Multiple( + TemporaryTable_ComplexObjects_EntitiesPerOperation + ); [Benchmark(Baseline = true)] [BenchmarkCategory(TemporaryTable_ComplexObjects_Category)] @@ -127,64 +169,22 @@ .. this.connection.Query( ), ]; - private readonly List temporaryTable_ComplexObjects_Entities = Generate.Multiple( - TemporaryTable_ComplexObjects_EntitiesPerOperation - ); - - private const string CreateTempEntitiesTableSql = """ - CREATE TEMP TABLE Entities ( - Id INTEGER, - BooleanValue INTEGER, - BytesValue BLOB, - ByteValue INTEGER, - CharValue TEXT, - DateTimeValue TEXT, - DecimalValue TEXT, - DoubleValue REAL, - EnumValue TEXT, - Int16Value INTEGER, - Int32Value INTEGER, - Int64Value INTEGER, - SingleValue REAL, - StringValue TEXT - ) - """; - - private const string InsertIntoTempEntities = """ - INSERT INTO temp.Entities ( - Id, - BooleanValue, - BytesValue, - ByteValue, - CharValue, - DateTimeValue, - DecimalValue, - DoubleValue, - EnumValue, - Int16Value, - Int32Value, - Int64Value, - SingleValue, - StringValue - ) - VALUES ( - @Id, - @BooleanValue, - @BytesValue, - @ByteValue, - @CharValue, - @DateTimeValue, - @DecimalValue, - @DoubleValue, - @EnumValue, - @Int16Value, - @Int32Value, - @Int64Value, - @SingleValue, - @StringValue - ) - """; + [GlobalCleanup( + Targets = [ + nameof(TemporaryTable_ComplexObjects_Command), + nameof(TemporaryTable_ComplexObjects_Dapper), + nameof(TemporaryTable_ComplexObjects_DbConnectionPlus), + ] + )] + public void TemporaryTable_ComplexObjects__Cleanup() => this.connection.Dispose(); - private const string TemporaryTable_ComplexObjects_Category = "TemporaryTable_ComplexObjects"; - private const int TemporaryTable_ComplexObjects_EntitiesPerOperation = 250; + [GlobalSetup( + Targets = [ + nameof(TemporaryTable_ComplexObjects_Command), + nameof(TemporaryTable_ComplexObjects_Dapper), + nameof(TemporaryTable_ComplexObjects_DbConnectionPlus), + ] + )] + public void TemporaryTable_ComplexObjects__Setup() => + this.SetupDatabase(TemporaryTable_ComplexObjects_EntitiesPerOperation); } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ScalarValues.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ScalarValues.cs index e141783..94e3747 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ScalarValues.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.TemporaryTable_ScalarValues.cs @@ -7,23 +7,13 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { - [GlobalCleanup( - Targets = [ - nameof(TemporaryTable_ScalarValues_Command), - nameof(TemporaryTable_ScalarValues_Dapper), - nameof(TemporaryTable_ScalarValues_DbConnectionPlus), - ] - )] - public void TemporaryTable_ScalarValues__Cleanup() => this.connection.Dispose(); + private const string TemporaryTable_ScalarValues_Category = "TemporaryTable_ScalarValues"; + private const int TemporaryTable_ScalarValues_ValuesPerOperation = 5000; - [GlobalSetup( - Targets = [ - nameof(TemporaryTable_ScalarValues_Command), - nameof(TemporaryTable_ScalarValues_Dapper), - nameof(TemporaryTable_ScalarValues_DbConnectionPlus), - ] - )] - public void TemporaryTable_ScalarValues__Setup() => this.SetupDatabase(0); + private readonly List temporaryTable_ScalarValues_Values = + [ + .. Enumerable.Range(0, TemporaryTable_ScalarValues_ValuesPerOperation).Select(a => (long)a), + ]; [Benchmark(Baseline = true)] [BenchmarkCategory(TemporaryTable_ScalarValues_Category)] @@ -96,11 +86,21 @@ .. this.connection.Query( ), ]; - private readonly List temporaryTable_ScalarValues_Values = - [ - .. Enumerable.Range(0, TemporaryTable_ScalarValues_ValuesPerOperation).Select(a => (long)a), - ]; + [GlobalCleanup( + Targets = [ + nameof(TemporaryTable_ScalarValues_Command), + nameof(TemporaryTable_ScalarValues_Dapper), + nameof(TemporaryTable_ScalarValues_DbConnectionPlus), + ] + )] + public void TemporaryTable_ScalarValues__Cleanup() => this.connection.Dispose(); - private const string TemporaryTable_ScalarValues_Category = "TemporaryTable_ScalarValues"; - private const int TemporaryTable_ScalarValues_ValuesPerOperation = 5000; + [GlobalSetup( + Targets = [ + nameof(TemporaryTable_ScalarValues_Command), + nameof(TemporaryTable_ScalarValues_Dapper), + nameof(TemporaryTable_ScalarValues_DbConnectionPlus), + ] + )] + public void TemporaryTable_ScalarValues__Setup() => this.SetupDatabase(0); } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntities.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntities.cs index e75bcce..905027a 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntities.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntities.cs @@ -7,44 +7,12 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { - [GlobalCleanup( - Targets = [ - nameof(UpdateEntities_Command), - nameof(UpdateEntities_Dapper), - nameof(UpdateEntities_DbConnectionPlus), - ] - )] - public void UpdateEntities__Cleanup() => this.connection.Dispose(); - - [GlobalSetup( - Targets = [ - nameof(UpdateEntities_Command), - nameof(UpdateEntities_Dapper), - nameof(UpdateEntities_DbConnectionPlus), - ] - )] - public void UpdateEntities__Setup() - { - this.SetupDatabase(UpdateEntities_EntitiesPerOperation); - - // See the note on UpdateEntity__Setup: generating the updated entities inside the benchmark charged their - // generation to all three implementations, and a single pre-generated set would make every invocation after - // the first write the values that are already stored. - this.updateEntities_ModifiedEntitiesPool = - [ - .. Enumerable - .Range(0, UpdateEntities_UpdatedEntitiesPoolSize) - .Select(_ => Generate.UpdatesFor(this.entitiesInDb)), - ]; - } - - private List UpdateEntities_GetNextModifiedEntities() - { - this.updateEntities_ModifiedEntitiesPoolIndex = - (this.updateEntities_ModifiedEntitiesPoolIndex + 1) % UpdateEntities_UpdatedEntitiesPoolSize; + private const string UpdateEntities_Category = "UpdateEntities"; + private const int UpdateEntities_EntitiesPerOperation = 100; + private const int UpdateEntities_UpdatedEntitiesPoolSize = 8; - return this.updateEntities_ModifiedEntitiesPool[this.updateEntities_ModifiedEntitiesPoolIndex]; - } + private List> updateEntities_ModifiedEntitiesPool = null!; + private int updateEntities_ModifiedEntitiesPoolIndex; [Benchmark(Baseline = true)] [BenchmarkCategory(UpdateEntities_Category)] @@ -110,10 +78,42 @@ public void UpdateEntities_Dapper() => public void UpdateEntities_DbConnectionPlus() => this.connection.UpdateEntities(this.UpdateEntities_GetNextModifiedEntities()); - private List> updateEntities_ModifiedEntitiesPool = null!; - private int updateEntities_ModifiedEntitiesPoolIndex; + [GlobalCleanup( + Targets = [ + nameof(UpdateEntities_Command), + nameof(UpdateEntities_Dapper), + nameof(UpdateEntities_DbConnectionPlus), + ] + )] + public void UpdateEntities__Cleanup() => this.connection.Dispose(); - private const string UpdateEntities_Category = "UpdateEntities"; - private const int UpdateEntities_EntitiesPerOperation = 100; - private const int UpdateEntities_UpdatedEntitiesPoolSize = 8; + [GlobalSetup( + Targets = [ + nameof(UpdateEntities_Command), + nameof(UpdateEntities_Dapper), + nameof(UpdateEntities_DbConnectionPlus), + ] + )] + public void UpdateEntities__Setup() + { + this.SetupDatabase(UpdateEntities_EntitiesPerOperation); + + // See the note on UpdateEntity__Setup: generating the updated entities inside the benchmark charged their + // generation to all three implementations, and a single pre-generated set would make every invocation after + // the first write the values that are already stored. + this.updateEntities_ModifiedEntitiesPool = + [ + .. Enumerable + .Range(0, UpdateEntities_UpdatedEntitiesPoolSize) + .Select(_ => Generate.UpdatesFor(this.entitiesInDb)), + ]; + } + + private List UpdateEntities_GetNextModifiedEntities() + { + this.updateEntities_ModifiedEntitiesPoolIndex = + (this.updateEntities_ModifiedEntitiesPoolIndex + 1) % UpdateEntities_UpdatedEntitiesPoolSize; + + return this.updateEntities_ModifiedEntitiesPool[this.updateEntities_ModifiedEntitiesPoolIndex]; + } } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntity.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntity.cs index 1e56998..ef420a1 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntity.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.UpdateEntity.cs @@ -7,40 +7,11 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public partial class Benchmarks { - [GlobalCleanup( - Targets = [nameof(UpdateEntity_Command), nameof(UpdateEntity_Dapper), nameof(UpdateEntity_DbConnectionPlus)] - )] - public void UpdateEntity__Cleanup() => this.connection.Dispose(); - - [GlobalSetup( - Targets = [nameof(UpdateEntity_Command), nameof(UpdateEntity_Dapper), nameof(UpdateEntity_DbConnectionPlus)] - )] - public void UpdateEntity__Setup() - { - this.SetupDatabase(1); - - // Building the updated entity inside the benchmark charged its generation to all three implementations - - // including the DbCommand baseline and Dapper - which both dominated the measurement and hid changes in - // DbConnectionPlus behind a baseline that moved with them. - // - // A pool rather than a single entity, so that consecutive invocations write different values. Reusing one - // entity would mean every invocation after the first writes the values that are already stored, which is not - // what an update does in practice. - this.updateEntity_ModifiedEntitiesPool = - [ - .. Enumerable - .Range(0, UpdateEntity_UpdatedEntityPoolSize) - .Select(_ => Generate.UpdateFor(this.entitiesInDb[0])), - ]; - } - - private BenchmarkEntity UpdateEntity_GetNextModifiedEntity() - { - this.updateEntity_ModifiedEntitiesPoolIndex = - (this.updateEntity_ModifiedEntitiesPoolIndex + 1) % UpdateEntity_UpdatedEntityPoolSize; + private const string UpdateEntity_Category = "UpdateEntity"; + private const int UpdateEntity_UpdatedEntityPoolSize = 64; - return this.updateEntity_ModifiedEntitiesPool[this.updateEntity_ModifiedEntitiesPoolIndex]; - } + private List updateEntity_ModifiedEntitiesPool = null!; + private int updateEntity_ModifiedEntitiesPoolIndex; [Benchmark(Baseline = true)] [BenchmarkCategory(UpdateEntity_Category)] @@ -103,9 +74,38 @@ public void UpdateEntity_Dapper() => public void UpdateEntity_DbConnectionPlus() => this.connection.UpdateEntity(this.UpdateEntity_GetNextModifiedEntity()); - private List updateEntity_ModifiedEntitiesPool = null!; - private int updateEntity_ModifiedEntitiesPoolIndex; + [GlobalCleanup( + Targets = [nameof(UpdateEntity_Command), nameof(UpdateEntity_Dapper), nameof(UpdateEntity_DbConnectionPlus)] + )] + public void UpdateEntity__Cleanup() => this.connection.Dispose(); - private const string UpdateEntity_Category = "UpdateEntity"; - private const int UpdateEntity_UpdatedEntityPoolSize = 64; + [GlobalSetup( + Targets = [nameof(UpdateEntity_Command), nameof(UpdateEntity_Dapper), nameof(UpdateEntity_DbConnectionPlus)] + )] + public void UpdateEntity__Setup() + { + this.SetupDatabase(1); + + // Building the updated entity inside the benchmark charged its generation to all three implementations - + // including the DbCommand baseline and Dapper - which both dominated the measurement and hid changes in + // DbConnectionPlus behind a baseline that moved with them. + // + // A pool rather than a single entity, so that consecutive invocations write different values. Reusing one + // entity would mean every invocation after the first writes the values that are already stored, which is not + // what an update does in practice. + this.updateEntity_ModifiedEntitiesPool = + [ + .. Enumerable + .Range(0, UpdateEntity_UpdatedEntityPoolSize) + .Select(_ => Generate.UpdateFor(this.entitiesInDb[0])), + ]; + } + + private BenchmarkEntity UpdateEntity_GetNextModifiedEntity() + { + this.updateEntity_ModifiedEntitiesPoolIndex = + (this.updateEntity_ModifiedEntitiesPoolIndex + 1) % UpdateEntity_UpdatedEntityPoolSize; + + return this.updateEntity_ModifiedEntitiesPool[this.updateEntity_ModifiedEntitiesPoolIndex]; + } } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.cs b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.cs index 475c95f..3dc93f4 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/Benchmarks.cs @@ -13,6 +13,35 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; [Config(typeof(BenchmarksConfig))] public partial class Benchmarks { + /* + * INTEGER PRIMARY KEY makes Id an alias for the rowid, so lookups by Id are b-tree descents instead of + * full table scans. Without it every "WHERE Id = ?" scanned the whole table, and that scan dominated the delete, + * update, exists and scalar benchmarks and made their results a function of the seeded row count rather than of + * the code under test. + */ + private const string CreateEntityTableSql = """ + CREATE TABLE Entity + ( + Id INTEGER PRIMARY KEY, + BooleanValue INTEGER, + BytesValue BLOB, + ByteValue INTEGER, + CharValue TEXT, + DateTimeValue TEXT, + DecimalValue TEXT, + DoubleValue REAL, + EnumValue TEXT, + Int16Value INTEGER, + Int32Value INTEGER, + Int64Value INTEGER, + SingleValue REAL, + StringValue TEXT + ); + """; + + private SqliteConnection connection = null!; + private List entitiesInDb = null!; + static Benchmarks() => DbConnectionPlusConfiguration.Instance.UseSqlite(); public Benchmarks() @@ -27,25 +56,6 @@ public Benchmarks() } } - private void SetupDatabase(int numberOfEntities) - { - this.connection?.Dispose(); - - this.connection = new("Data Source=:memory:"); - this.connection.Open(); - - using var createEntityTableCommand = this.connection.CreateCommand(); - createEntityTableCommand.CommandText = CreateEntityTableSql; - createEntityTableCommand.ExecuteNonQuery(); - - using var transaction = this.connection.BeginTransaction(); - - this.entitiesInDb = Generate.Multiple(numberOfEntities); - this.connection.InsertEntities(this.entitiesInDb, transaction); - - transaction.Commit(); - } - private static void PopulateEntityParameters(BenchmarkEntity entity, Dictionary parameters) { parameters["Id"].Value = entity.Id; @@ -92,32 +102,22 @@ private static BenchmarkEntity ReadEntity(IDataReader dataReader) }; } - private SqliteConnection connection = null!; - private List entitiesInDb = null!; + private void SetupDatabase(int numberOfEntities) + { + this.connection?.Dispose(); - /* - * INTEGER PRIMARY KEY makes Id an alias for the rowid, so lookups by Id are b-tree descents instead of - * full table scans. Without it every "WHERE Id = ?" scanned the whole table, and that scan dominated the delete, - * update, exists and scalar benchmarks and made their results a function of the seeded row count rather than of - * the code under test. - */ - private const string CreateEntityTableSql = """ - CREATE TABLE Entity - ( - Id INTEGER PRIMARY KEY, - BooleanValue INTEGER, - BytesValue BLOB, - ByteValue INTEGER, - CharValue TEXT, - DateTimeValue TEXT, - DecimalValue TEXT, - DoubleValue REAL, - EnumValue TEXT, - Int16Value INTEGER, - Int32Value INTEGER, - Int64Value INTEGER, - SingleValue REAL, - StringValue TEXT - ); - """; + this.connection = new("Data Source=:memory:"); + this.connection.Open(); + + using var createEntityTableCommand = this.connection.CreateCommand(); + createEntityTableCommand.CommandText = CreateEntityTableSql; + createEntityTableCommand.ExecuteNonQuery(); + + using var transaction = this.connection.BeginTransaction(); + + this.entitiesInDb = Generate.Multiple(numberOfEntities); + this.connection.InsertEntities(this.entitiesInDb, transaction); + + transaction.Commit(); + } } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksConfig.cs b/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksConfig.cs index fd6570a..a8eff1f 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksConfig.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksConfig.cs @@ -10,6 +10,11 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks; public class BenchmarksConfig : ManualConfig { + public const string AotJobId = "AOT"; + + // The Job column of the summary shows these. + public const string JitJobId = "JIT"; + public BenchmarksConfig() { this.Orderer = new BenchmarksOrderer(); @@ -52,8 +57,4 @@ private static Job CreateJob(string id) => .WithMaxIterationCount(20) // Since DbConnectionPlus will mostly be used in server applications, we test with server GC. .WithGcServer(true); - - // The Job column of the summary shows these. - public const string JitJobId = "JIT"; - public const string AotJobId = "AOT"; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksOrderer.cs b/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksOrderer.cs index 4fef65f..bf29bb4 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksOrderer.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/BenchmarksOrderer.cs @@ -40,17 +40,17 @@ public IEnumerable> GetLogicalGroupOrder( public IEnumerable GetSummaryOrder(ImmutableArray benchmarksCases, Summary summary) => Sort(benchmarksCases); + // Ranked rather than sorted by name, so that JIT is reported before AOT instead of alphabetically. + private static int GetJobRank(BenchmarkCase benchmarkCase) => + benchmarkCase.Job.Id.Contains(BenchmarksConfig.JitJobId, StringComparison.Ordinal) ? 0 : 1; + + private static string GetLogicalGroupKey(BenchmarkCase benchmarkCase) => + $"{benchmarkCase.Descriptor.Categories.FirstOrDefault()}-{benchmarkCase.Job.Id}"; + private static IEnumerable Sort(ImmutableArray benchmarkCases) => benchmarkCases .OrderBy(a => a.Descriptor.Categories[0], StringComparer.Ordinal) .ThenBy(GetJobRank) .ThenByDescending(a => a.Descriptor.Baseline) .ThenBy(a => a.Descriptor.WorkloadMethod.Name, StringComparer.Ordinal); - - private static string GetLogicalGroupKey(BenchmarkCase benchmarkCase) => - $"{benchmarkCase.Descriptor.Categories.FirstOrDefault()}-{benchmarkCase.Job.Id}"; - - // Ranked rather than sorted by name, so that JIT is reported before AOT instead of alphabetically. - private static int GetJobRank(BenchmarkCase benchmarkCase) => - benchmarkCase.Job.Id.Contains(BenchmarksConfig.JitJobId, StringComparison.Ordinal) ? 0 : 1; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/TestData/BenchmarkEntity.cs b/benchmarks/DbConnectionPlus.Benchmarks/TestData/BenchmarkEntity.cs index 3d684d9..49df891 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/TestData/BenchmarkEntity.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/TestData/BenchmarkEntity.cs @@ -10,8 +10,8 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks.TestData; public record BenchmarkEntity { public bool BooleanValue { get; set; } - public byte[] BytesValue { get; set; } = null!; public byte ByteValue { get; set; } + public byte[] BytesValue { get; set; } = null!; public char CharValue { get; set; } public DateTime DateTimeValue { get; set; } public decimal DecimalValue { get; set; } diff --git a/benchmarks/DbConnectionPlus.Benchmarks/TestData/Generate.cs b/benchmarks/DbConnectionPlus.Benchmarks/TestData/Generate.cs index 9dd8ee2..127a846 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/TestData/Generate.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/TestData/Generate.cs @@ -22,11 +22,61 @@ namespace RentADeveloper.DbConnectionPlus.Benchmarks.TestData; // three for Double and Single, and alphabetic characters only for Char. public static class Generate { - public static BenchmarkEntity Single() => Create(NextId()); + private static readonly char[] characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray(); + + private static readonly DateTime dateTimeBase = new(2020, 1, 1, 0, 0, 0, DateTimeKind.Local); + + // Seeded, so that every process generates the same entities. + private static readonly Random random = new(20260813); + + // Guards random. The setup is single threaded today, but a shared unsynchronized Random silently starts + // returning zeroes once it is not, which would be invisible in a benchmark result. + private static readonly Lock syncRoot = new(); + + private static readonly string[] words = + [ + "lorem", + "ipsum", + "dolor", + "sit", + "amet", + "consectetur", + "adipiscing", + "elit", + "sed", + "do", + "eiusmod", + "tempor", + "incididunt", + "ut", + "labore", + "et", + "dolore", + "magna", + "aliqua", + "enim", + "ad", + "minim", + "veniam", + "quis", + "nostrud", + "exercitation", + "ullamco", + "laboris", + "nisi", + "aliquip", + "ex", + "ea", + "commodo", + ]; + + private static long nextId; public static List Multiple(int numberOfEntities) => [.. Enumerable.Range(0, numberOfEntities).Select(_ => Single())]; + public static BenchmarkEntity Single() => Create(NextId()); + public static BenchmarkEntity UpdateFor(BenchmarkEntity entity) { var updatedEntity = Create(entity.Id); @@ -69,8 +119,6 @@ private static BenchmarkEntity Create(long id) } } - private static long NextId() => Interlocked.Increment(ref nextId); - private static byte[] NextBytes(int count) { var bytes = new byte[count]; @@ -80,6 +128,8 @@ private static byte[] NextBytes(int count) return bytes; } + private static long NextId() => Interlocked.Increment(ref nextId); + private static string NextSentence() { var wordCount = random.Next(4, 9); @@ -94,54 +144,4 @@ private static string NextSentence() return string.Join(' ', sentence) + '.'; } - - private static long nextId; - - // Seeded, so that every process generates the same entities. - private static readonly Random random = new(20260813); - - // Guards random. The setup is single threaded today, but a shared unsynchronized Random silently starts - // returning zeroes once it is not, which would be invisible in a benchmark result. - private static readonly Lock syncRoot = new(); - - private static readonly char[] characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray(); - - private static readonly string[] words = - [ - "lorem", - "ipsum", - "dolor", - "sit", - "amet", - "consectetur", - "adipiscing", - "elit", - "sed", - "do", - "eiusmod", - "tempor", - "incididunt", - "ut", - "labore", - "et", - "dolore", - "magna", - "aliqua", - "enim", - "ad", - "minim", - "veniam", - "quis", - "nostrud", - "exercitation", - "ullamco", - "laboris", - "nisi", - "aliquip", - "ex", - "ea", - "commodo", - ]; - - private static readonly DateTime dateTimeBase = new(2020, 1, 1, 0, 0, 0, DateTimeKind.Local); } diff --git a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlDatabaseAdapter.cs b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlDatabaseAdapter.cs index 9eaee12..6676184 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlDatabaseAdapter.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlDatabaseAdapter.cs @@ -10,6 +10,29 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.MySql; /// public class MySqlDatabaseAdapter : IDatabaseAdapter { + private static readonly Dictionary typeToMySqlDataType = new() + { + { typeof(bool), "TINYINT(1)" }, + { typeof(byte), "TINYINT UNSIGNED" }, + { typeof(byte[]), "BLOB" }, + { typeof(char), "CHAR(1)" }, + { typeof(DateOnly), "DATE" }, + { typeof(DateTime), "DATETIME" }, + { typeof(decimal), "DECIMAL(65,30)" }, + { typeof(double), "DOUBLE" }, + { typeof(Guid), "CHAR(36)" }, + { typeof(short), "SMALLINT" }, + { typeof(int), "INT" }, + { typeof(long), "BIGINT" }, + { typeof(float), "FLOAT" }, + { typeof(string), "TEXT" }, + { typeof(TimeOnly), "TIME" }, + { typeof(TimeSpan), "TIME" }, + }; + + private readonly MySqlEntityManipulator entityManipulator; + private readonly MySqlTemporaryTableBuilder temporaryTableBuilder; + /// /// Initializes a new instance of the class. /// @@ -118,27 +141,4 @@ public bool WasSqlStatementCancelledByCancellationToken(Exception exception, Can // MySqlConnector does not support proper statement cancellation. return false; } - - private readonly MySqlEntityManipulator entityManipulator; - private readonly MySqlTemporaryTableBuilder temporaryTableBuilder; - - private static readonly Dictionary typeToMySqlDataType = new() - { - { typeof(bool), "TINYINT(1)" }, - { typeof(byte), "TINYINT UNSIGNED" }, - { typeof(byte[]), "BLOB" }, - { typeof(char), "CHAR(1)" }, - { typeof(DateOnly), "DATE" }, - { typeof(DateTime), "DATETIME" }, - { typeof(decimal), "DECIMAL(65,30)" }, - { typeof(double), "DOUBLE" }, - { typeof(Guid), "CHAR(36)" }, - { typeof(short), "SMALLINT" }, - { typeof(int), "INT" }, - { typeof(long), "BIGINT" }, - { typeof(float), "FLOAT" }, - { typeof(string), "TEXT" }, - { typeof(TimeOnly), "TIME" }, - { typeof(TimeSpan), "TIME" }, - }; } diff --git a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlEntityManipulator.cs index 244d650..b1a62fb 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlEntityManipulator.cs @@ -13,6 +13,10 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.MySql; /// internal class MySqlEntityManipulator : IEntityManipulator { + private readonly MySqlDatabaseAdapter databaseAdapter; + private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); /// /// Initializes a new instance of the class. /// @@ -666,6 +670,81 @@ await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, } } + /// + /// Updates the database generated properties of the provided entity from the provided data reader. + /// + /// The metadata for the entity type. + /// The data reader from which to read the values for the properties. + /// The entity to update. + /// A token that can be used to cancel the operation. + private static void UpdateDatabaseGeneratedProperties( + EntityTypeMetadata entityTypeMetadata, + DbDataReader reader, + object entity, + CancellationToken cancellationToken + ) + { + if (entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 && reader.Read()) + { + cancellationToken.ThrowIfCancellationRequested(); + + for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) + { + var property = entityTypeMetadata.DatabaseGeneratedProperties[i]; + + if (!property.CanWrite) + { + continue; + } + + var value = reader.GetValue(i); + + value = ValueConverter.ConvertValueToType(value, property.PropertyType); + + property.PropertySetter!(entity, value); + } + } + } + + /// + /// Asynchronously updates the database generated properties of the provided entity from the provided data + /// reader. + /// + /// The metadata for the entity type. + /// The data reader from which to read the values for the properties. + /// The entity to update. + /// A token that can be used to cancel the operation. + /// A task that represents the asynchronous operation. + private static async Task UpdateDatabaseGeneratedPropertiesAsync( + EntityTypeMetadata entityTypeMetadata, + DbDataReader reader, + object entity, + CancellationToken cancellationToken + ) + { + if ( + entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 + && await reader.ReadAsync(cancellationToken).ConfigureAwait(false) + ) + { + for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) + { + var property = entityTypeMetadata.DatabaseGeneratedProperties[i]; + + if (!property.CanWrite) + { + continue; + } + + var value = reader.GetValue(i); + + value = ValueConverter.ConvertValueToType(value, property.PropertyType); + + property.PropertySetter!(entity, value); + } + } + } + /// /// Creates a command to delete an entity. /// @@ -1126,84 +1205,4 @@ object entity this.databaseAdapter.BindParameterValue(parameter, propertyValue); } } - - /// - /// Updates the database generated properties of the provided entity from the provided data reader. - /// - /// The metadata for the entity type. - /// The data reader from which to read the values for the properties. - /// The entity to update. - /// A token that can be used to cancel the operation. - private static void UpdateDatabaseGeneratedProperties( - EntityTypeMetadata entityTypeMetadata, - DbDataReader reader, - object entity, - CancellationToken cancellationToken - ) - { - if (entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 && reader.Read()) - { - cancellationToken.ThrowIfCancellationRequested(); - - for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) - { - var property = entityTypeMetadata.DatabaseGeneratedProperties[i]; - - if (!property.CanWrite) - { - continue; - } - - var value = reader.GetValue(i); - - value = ValueConverter.ConvertValueToType(value, property.PropertyType); - - property.PropertySetter!(entity, value); - } - } - } - - /// - /// Asynchronously updates the database generated properties of the provided entity from the provided data - /// reader. - /// - /// The metadata for the entity type. - /// The data reader from which to read the values for the properties. - /// The entity to update. - /// A token that can be used to cancel the operation. - /// A task that represents the asynchronous operation. - private static async Task UpdateDatabaseGeneratedPropertiesAsync( - EntityTypeMetadata entityTypeMetadata, - DbDataReader reader, - object entity, - CancellationToken cancellationToken - ) - { - if ( - entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 - && await reader.ReadAsync(cancellationToken).ConfigureAwait(false) - ) - { - for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) - { - var property = entityTypeMetadata.DatabaseGeneratedProperties[i]; - - if (!property.CanWrite) - { - continue; - } - - var value = reader.GetValue(i); - - value = ValueConverter.ConvertValueToType(value, property.PropertyType); - - property.PropertySetter!(entity, value); - } - } - } - - private readonly MySqlDatabaseAdapter databaseAdapter; - private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); - private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); - private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); } diff --git a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlTemporaryTableBuilder.cs b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlTemporaryTableBuilder.cs index 0c2a0d9..66386ec 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlTemporaryTableBuilder.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlTemporaryTableBuilder.cs @@ -16,6 +16,8 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.MySql; /// internal class MySqlTemporaryTableBuilder : ITemporaryTableBuilder { + private readonly MySqlDatabaseAdapter databaseAdapter; + /// /// Initializes a new instance of the class. /// @@ -246,86 +248,6 @@ public async Task BuildTemporaryTableAsync( ); } - /// - /// Builds an SQL code to create a multi-column temporary table to be populated with objects of the type - /// . - /// - /// The name of the table to create. - /// The type of objects with which to populate the table. - /// The mode to use to serialize values. - /// The built SQL code. - private string BuildCreateMultiColumnTemporaryTableSqlCode( - string tableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type objectsType, - EnumSerializationMode enumSerializationMode - ) - { - using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); - - sqlBuilder.Append("CREATE TEMPORARY TABLE `"); - sqlBuilder.Append(tableName); - sqlBuilder.AppendLine("`"); - - sqlBuilder.Append(Constants.Indent); - sqlBuilder.Append("("); - - var properties = EntityHelper.GetEntityTypeMetadata(objectsType).MappedProperties.Where(a => a.CanRead); - - var prependSeparator = false; - - foreach (var property in properties) - { - if (prependSeparator) - { - sqlBuilder.Append(", "); - } - - sqlBuilder.Append("`"); - sqlBuilder.Append(property.ColumnName); - sqlBuilder.Append("` "); - - var propertyType = property.PropertyType; - - sqlBuilder.Append(this.databaseAdapter.GetDataType(propertyType, enumSerializationMode)); - - prependSeparator = true; - } - - sqlBuilder.AppendLine(")"); - - return sqlBuilder.ToString(); - } - - /// - /// Builds an SQL code to create a single-column temporary table to be populated with values of the type - /// . - /// - /// The name of the table to create. - /// The type of values with which the table will be populated. - /// The mode to use to serialize values. - /// The built SQL code. - private string BuildCreateSingleColumnTemporaryTableSqlCode( - string tableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, - EnumSerializationMode enumSerializationMode - ) - { - using var sqlBuilder = new ValueStringBuilder(stackalloc char[100]); - - sqlBuilder.Append("CREATE TEMPORARY TABLE `"); - sqlBuilder.Append(tableName); - sqlBuilder.AppendLine("`"); - - sqlBuilder.Append(Constants.Indent); - sqlBuilder.Append("(`"); - sqlBuilder.Append(Constants.SingleColumnTemporaryTableColumnName); - sqlBuilder.Append("` "); - sqlBuilder.Append(this.databaseAdapter.GetDataType(valuesType, enumSerializationMode)); - sqlBuilder.AppendLine(")"); - - return sqlBuilder.ToString(); - } - /// /// Creates a that reads data from the specified sequence of values. /// @@ -442,5 +364,83 @@ private static async ValueTask DropTemporaryTableAsync( await command.ExecuteNonQueryAsync().ConfigureAwait(false); } - private readonly MySqlDatabaseAdapter databaseAdapter; + /// + /// Builds an SQL code to create a multi-column temporary table to be populated with objects of the type + /// . + /// + /// The name of the table to create. + /// The type of objects with which to populate the table. + /// The mode to use to serialize values. + /// The built SQL code. + private string BuildCreateMultiColumnTemporaryTableSqlCode( + string tableName, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type objectsType, + EnumSerializationMode enumSerializationMode + ) + { + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); + + sqlBuilder.Append("CREATE TEMPORARY TABLE `"); + sqlBuilder.Append(tableName); + sqlBuilder.AppendLine("`"); + + sqlBuilder.Append(Constants.Indent); + sqlBuilder.Append("("); + + var properties = EntityHelper.GetEntityTypeMetadata(objectsType).MappedProperties.Where(a => a.CanRead); + + var prependSeparator = false; + + foreach (var property in properties) + { + if (prependSeparator) + { + sqlBuilder.Append(", "); + } + + sqlBuilder.Append("`"); + sqlBuilder.Append(property.ColumnName); + sqlBuilder.Append("` "); + + var propertyType = property.PropertyType; + + sqlBuilder.Append(this.databaseAdapter.GetDataType(propertyType, enumSerializationMode)); + + prependSeparator = true; + } + + sqlBuilder.AppendLine(")"); + + return sqlBuilder.ToString(); + } + + /// + /// Builds an SQL code to create a single-column temporary table to be populated with values of the type + /// . + /// + /// The name of the table to create. + /// The type of values with which the table will be populated. + /// The mode to use to serialize values. + /// The built SQL code. + private string BuildCreateSingleColumnTemporaryTableSqlCode( + string tableName, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, + EnumSerializationMode enumSerializationMode + ) + { + using var sqlBuilder = new ValueStringBuilder(stackalloc char[100]); + + sqlBuilder.Append("CREATE TEMPORARY TABLE `"); + sqlBuilder.Append(tableName); + sqlBuilder.AppendLine("`"); + + sqlBuilder.Append(Constants.Indent); + sqlBuilder.Append("(`"); + sqlBuilder.Append(Constants.SingleColumnTemporaryTableColumnName); + sqlBuilder.Append("` "); + sqlBuilder.Append(this.databaseAdapter.GetDataType(valuesType, enumSerializationMode)); + sqlBuilder.AppendLine(")"); + + return sqlBuilder.ToString(); + } } diff --git a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleDatabaseAdapter.cs b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleDatabaseAdapter.cs index df208e6..9172a5c 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleDatabaseAdapter.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleDatabaseAdapter.cs @@ -11,6 +11,52 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.Oracle; /// public class OracleDatabaseAdapter : IDatabaseAdapter { + private static readonly Dictionary typeToDbType = new() + { + { typeof(bool), DbType.Boolean }, + { typeof(byte), DbType.Byte }, + { typeof(byte[]), DbType.Binary }, + { typeof(char), DbType.StringFixedLength }, + { typeof(DateOnly), DbType.Date }, + { typeof(DateTime), DbType.DateTime }, + { typeof(DateTimeOffset), DbType.DateTimeOffset }, + { typeof(decimal), DbType.Decimal }, + { typeof(double), DbType.Double }, + { typeof(Guid), DbType.Guid }, + { typeof(short), DbType.Int16 }, + { typeof(int), DbType.Int32 }, + { typeof(long), DbType.Int64 }, + { typeof(float), DbType.Single }, + { typeof(string), DbType.String }, + { typeof(TimeOnly), DbType.Time }, + { typeof(TimeSpan), DbType.Time }, + }; + + private static readonly Dictionary typeToOracleDataType = new() + { + { typeof(bool), "NUMBER(1)" }, + { typeof(byte), "NUMBER(3)" }, + { typeof(byte[]), "RAW(2000)" }, + { typeof(char), "CHAR(1)" }, + { typeof(DateOnly), "DATE" }, + { typeof(DateTime), "TIMESTAMP" }, + { typeof(DateTimeOffset), "TIMESTAMP WITH TIME ZONE" }, + { typeof(decimal), "NUMBER(28,10)" }, + { typeof(double), "BINARY_DOUBLE" }, + { typeof(Guid), "RAW(16)" }, + { typeof(short), "NUMBER(5)" }, + { typeof(int), "NUMBER(10)" }, + { typeof(long), "NUMBER(19)" }, + { typeof(float), "BINARY_FLOAT" }, + { typeof(string), "NVARCHAR2(2000)" }, + { typeof(TimeOnly), "INTERVAL DAY TO SECOND" }, + { typeof(TimeSpan), "INTERVAL DAY TO SECOND" }, + }; + + private readonly OracleEntityManipulator entityManipulator; + private readonly ConcurrentDictionary supportsTemporaryTablesPerConnectionString = []; + private readonly OracleTemporaryTableBuilder temporaryTableBuilder; + /// /// Initializes a new instance of the class. /// @@ -20,6 +66,34 @@ public OracleDatabaseAdapter() this.temporaryTableBuilder = new(this); } + /// + /// + /// Determines whether the temporary tables feature of DbConnectionPlus + /// () is allowed to be used with Oracle databases. + /// Disabled by default. + /// + /// + /// WARNING: + /// Before enabling this feature, read the following note: + /// When using the temporary tables feature of DbConnectionPlus with an Oracle database, please be aware of the + /// following implications: + /// The temporary tables feature of DbConnectionPlus creates private temporary tables and drops them after use. + /// Unfortunately DDL statements (like creating and dropping a private temporary table) cause an implicit commit of + /// the current transaction in an Oracle database. + /// That means if you use the temporary tables feature inside an explicit transaction, the transaction will be + /// committed when the temporary table is created and again when it is dropped! + /// + /// + /// Therefore, when using DbConnectionPlus with Oracle databases, avoid using the temporary tables feature inside + /// explicit transactions or at least be aware of the implications. + /// You have been warned! + /// + /// + /// + /// If set to , attempting to use the temporary tables feature will throw an exception. + /// + public static bool AllowTemporaryTables { get; set; } + /// public IEntityManipulator EntityManipulator => this.entityManipulator; @@ -238,34 +312,6 @@ public bool WasSqlStatementCancelledByCancellationToken(Exception exception, Can return false; } - /// - /// - /// Determines whether the temporary tables feature of DbConnectionPlus - /// () is allowed to be used with Oracle databases. - /// Disabled by default. - /// - /// - /// WARNING: - /// Before enabling this feature, read the following note: - /// When using the temporary tables feature of DbConnectionPlus with an Oracle database, please be aware of the - /// following implications: - /// The temporary tables feature of DbConnectionPlus creates private temporary tables and drops them after use. - /// Unfortunately DDL statements (like creating and dropping a private temporary table) cause an implicit commit of - /// the current transaction in an Oracle database. - /// That means if you use the temporary tables feature inside an explicit transaction, the transaction will be - /// committed when the temporary table is created and again when it is dropped! - /// - /// - /// Therefore, when using DbConnectionPlus with Oracle databases, avoid using the temporary tables feature inside - /// explicit transactions or at least be aware of the implications. - /// You have been warned! - /// - /// - /// - /// If set to , attempting to use the temporary tables feature will throw an exception. - /// - public static bool AllowTemporaryTables { get; set; } - /// /// Throws an indicating that the temporary tables feature of /// DbConnectionPlus is disabled for Oracle databases. @@ -278,50 +324,4 @@ internal static void ThrowTemporaryTablesFeatureIsDisabledException() => + "to true, but be sure to read the documentation first, because enabling this feature has implications " + "for transaction management." ); - - private readonly OracleEntityManipulator entityManipulator; - private readonly ConcurrentDictionary supportsTemporaryTablesPerConnectionString = []; - private readonly OracleTemporaryTableBuilder temporaryTableBuilder; - - private static readonly Dictionary typeToDbType = new() - { - { typeof(bool), DbType.Boolean }, - { typeof(byte), DbType.Byte }, - { typeof(byte[]), DbType.Binary }, - { typeof(char), DbType.StringFixedLength }, - { typeof(DateOnly), DbType.Date }, - { typeof(DateTime), DbType.DateTime }, - { typeof(DateTimeOffset), DbType.DateTimeOffset }, - { typeof(decimal), DbType.Decimal }, - { typeof(double), DbType.Double }, - { typeof(Guid), DbType.Guid }, - { typeof(short), DbType.Int16 }, - { typeof(int), DbType.Int32 }, - { typeof(long), DbType.Int64 }, - { typeof(float), DbType.Single }, - { typeof(string), DbType.String }, - { typeof(TimeOnly), DbType.Time }, - { typeof(TimeSpan), DbType.Time }, - }; - - private static readonly Dictionary typeToOracleDataType = new() - { - { typeof(bool), "NUMBER(1)" }, - { typeof(byte), "NUMBER(3)" }, - { typeof(byte[]), "RAW(2000)" }, - { typeof(char), "CHAR(1)" }, - { typeof(DateOnly), "DATE" }, - { typeof(DateTime), "TIMESTAMP" }, - { typeof(DateTimeOffset), "TIMESTAMP WITH TIME ZONE" }, - { typeof(decimal), "NUMBER(28,10)" }, - { typeof(double), "BINARY_DOUBLE" }, - { typeof(Guid), "RAW(16)" }, - { typeof(short), "NUMBER(5)" }, - { typeof(int), "NUMBER(10)" }, - { typeof(long), "NUMBER(19)" }, - { typeof(float), "BINARY_FLOAT" }, - { typeof(string), "NVARCHAR2(2000)" }, - { typeof(TimeOnly), "INTERVAL DAY TO SECOND" }, - { typeof(TimeSpan), "INTERVAL DAY TO SECOND" }, - }; } diff --git a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleEntityManipulator.cs index 761814f..07a45af 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleEntityManipulator.cs @@ -14,6 +14,11 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.Oracle; /// The database adapter to use to manipulate entities. internal class OracleEntityManipulator(OracleDatabaseAdapter databaseAdapter) : IEntityManipulator { + private readonly OracleDatabaseAdapter databaseAdapter = databaseAdapter; + private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); + /// public int DeleteEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, @@ -636,6 +641,37 @@ CancellationToken cancellationToken } } + /// + /// Updates the database generated properties of the provided entity from the provided output parameters. + /// + /// The metadata for the entity type. + /// The output parameters from which to read the values for the properties. + /// The entity to update. + private static void UpdateDatabaseGeneratedProperties( + EntityTypeMetadata entityTypeMetadata, + DbParameter[] outputParameters, + object entity + ) + { + if (entityTypeMetadata.DatabaseGeneratedProperties.Count > 0) + { + for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) + { + var property = entityTypeMetadata.DatabaseGeneratedProperties[i]; + if (!property.CanWrite) + { + continue; + } + + var value = outputParameters[i].Value; + + value = ValueConverter.ConvertValueToType(value, property.PropertyType); + + property.PropertySetter!(entity, value); + } + } + } + /// /// Creates a command to delete an entity. /// @@ -1106,40 +1142,4 @@ object entity this.databaseAdapter.BindParameterValue(parameter, propertyValue); } } - - /// - /// Updates the database generated properties of the provided entity from the provided output parameters. - /// - /// The metadata for the entity type. - /// The output parameters from which to read the values for the properties. - /// The entity to update. - private static void UpdateDatabaseGeneratedProperties( - EntityTypeMetadata entityTypeMetadata, - DbParameter[] outputParameters, - object entity - ) - { - if (entityTypeMetadata.DatabaseGeneratedProperties.Count > 0) - { - for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) - { - var property = entityTypeMetadata.DatabaseGeneratedProperties[i]; - if (!property.CanWrite) - { - continue; - } - - var value = outputParameters[i].Value; - - value = ValueConverter.ConvertValueToType(value, property.PropertyType); - - property.PropertySetter!(entity, value); - } - } - } - - private readonly OracleDatabaseAdapter databaseAdapter = databaseAdapter; - private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); - private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); - private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); } diff --git a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleTemporaryTableBuilder.cs b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleTemporaryTableBuilder.cs index 49c03a1..b4c04f0 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleTemporaryTableBuilder.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleTemporaryTableBuilder.cs @@ -15,6 +15,8 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.Oracle; /// internal class OracleTemporaryTableBuilder : ITemporaryTableBuilder { + private readonly OracleDatabaseAdapter databaseAdapter; + /// /// Initializes a new instance of the class. /// @@ -230,6 +232,154 @@ await this.PopulateTemporaryTableAsync( ); } + /// + /// Builds an SQL code to insert data from the specified data reader into the specified temporary table. + /// + /// The quoted name of the table to insert data into. + /// The type of values with which to populate the table. + /// The data reader to read data from. + /// A tuple containing the insert SQL code and the parameters to use. + private static (string SqlCode, OracleParameter[] Parameters) BuildInsertSqlCode( + string quotedTableName, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, + DbDataReader dataReader + ) + { + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); + + sqlBuilder.Append("INSERT INTO "); + sqlBuilder.AppendLine(quotedTableName); + + sqlBuilder.Append(Constants.Indent); + sqlBuilder.Append("("); + + var fieldCount = dataReader.FieldCount; + var parameters = new OracleParameter[fieldCount]; + + if (valuesType.IsBuiltInTypeOrNullableBuiltInType() || valuesType.IsEnumOrNullableEnumType()) + { + sqlBuilder.Append("\""); + sqlBuilder.Append(Constants.SingleColumnTemporaryTableColumnName); + sqlBuilder.Append("\""); + + parameters[0] = new() { ParameterName = Constants.SingleColumnTemporaryTableColumnName }; + } + else + { + var properties = EntityHelper + .GetEntityTypeMetadata(valuesType) + .MappedProperties.Where(a => a.CanRead) + .ToList(); + + for (var i = 0; i < properties.Count; i++) + { + if (i > 0) + { + sqlBuilder.Append(", "); + } + + var property = properties[i]; + + sqlBuilder.Append('"'); + sqlBuilder.Append(property.ColumnName); + sqlBuilder.Append('"'); + + parameters[i] = new() { ParameterName = property.PropertyName }; + } + } + + sqlBuilder.AppendLine(")"); + + sqlBuilder.AppendLine("VALUES"); + + sqlBuilder.Append(Constants.Indent); + sqlBuilder.Append("("); + + for (var i = 0; i < fieldCount; i++) + { + if (i > 0) + { + sqlBuilder.Append(", "); + } + + sqlBuilder.Append(":\"" + parameters[i].ParameterName + "\""); + } + + sqlBuilder.AppendLine(")"); + + return (sqlBuilder.ToString(), parameters); + } + + /// + /// Creates a that reads data from the specified sequence of values. + /// + /// The sequence containing the values to be read. + /// The type of values in . + /// A that provides access to the data in . + private static EnumerableReader CreateValuesDataReader( + IEnumerable values, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType + ) + { + if (valuesType.IsBuiltInTypeOrNullableBuiltInType() || valuesType.IsEnumOrNullableEnumType()) + { + return new EnumerableReader(values, valuesType, Constants.SingleColumnTemporaryTableColumnName); + } + + return new EnumerableReader( + values, + [.. EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a.CanRead)], + EnumerableReaderOptions.None + ); + } + + /// + /// Drops the temporary table with the specified name. + /// + /// The quoted name of the table to drop. + /// The connection to use to drop the table. + /// The transaction within to drop the table. + private static void DropTemporaryTable( + string quotedTableName, + OracleConnection connection, + OracleTransaction? transaction + ) + { + using var command = connection.CreateCommand(); + + command.CommandText = $"DROP TABLE {quotedTableName}"; + command.Transaction = transaction; + + DbConnectionExtensions.OnBeforeExecutingCommand(command, []); + + command.ExecuteNonQuery(); + } + + /// + /// Asynchronously drops the temporary table with the specified name. + /// + /// The quoted name of the table to drop. + /// The connection to use to drop the table. + /// The transaction within to drop the table. + /// A task representing the asynchronous operation. + private static async ValueTask DropTemporaryTableAsync( + string quotedTableName, + OracleConnection connection, + OracleTransaction? transaction + ) + { +#pragma warning disable CA2007 + await using var command = connection.CreateCommand(); +#pragma warning restore CA2007 + + command.CommandText = $"DROP TABLE {quotedTableName}"; + command.Transaction = transaction; + + DbConnectionExtensions.OnBeforeExecutingCommand(command, []); + + await command.ExecuteNonQueryAsync().ConfigureAwait(false); + } + /// /// Builds an SQL code to create a multi-column temporary table to be populated with objects of the type /// . @@ -439,154 +589,4 @@ CancellationToken cancellationToken await insertCommand.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false); } } - - /// - /// Builds an SQL code to insert data from the specified data reader into the specified temporary table. - /// - /// The quoted name of the table to insert data into. - /// The type of values with which to populate the table. - /// The data reader to read data from. - /// A tuple containing the insert SQL code and the parameters to use. - private static (string SqlCode, OracleParameter[] Parameters) BuildInsertSqlCode( - string quotedTableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, - DbDataReader dataReader - ) - { - using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); - - sqlBuilder.Append("INSERT INTO "); - sqlBuilder.AppendLine(quotedTableName); - - sqlBuilder.Append(Constants.Indent); - sqlBuilder.Append("("); - - var fieldCount = dataReader.FieldCount; - var parameters = new OracleParameter[fieldCount]; - - if (valuesType.IsBuiltInTypeOrNullableBuiltInType() || valuesType.IsEnumOrNullableEnumType()) - { - sqlBuilder.Append("\""); - sqlBuilder.Append(Constants.SingleColumnTemporaryTableColumnName); - sqlBuilder.Append("\""); - - parameters[0] = new() { ParameterName = Constants.SingleColumnTemporaryTableColumnName }; - } - else - { - var properties = EntityHelper - .GetEntityTypeMetadata(valuesType) - .MappedProperties.Where(a => a.CanRead) - .ToList(); - - for (var i = 0; i < properties.Count; i++) - { - if (i > 0) - { - sqlBuilder.Append(", "); - } - - var property = properties[i]; - - sqlBuilder.Append('"'); - sqlBuilder.Append(property.ColumnName); - sqlBuilder.Append('"'); - - parameters[i] = new() { ParameterName = property.PropertyName }; - } - } - - sqlBuilder.AppendLine(")"); - - sqlBuilder.AppendLine("VALUES"); - - sqlBuilder.Append(Constants.Indent); - sqlBuilder.Append("("); - - for (var i = 0; i < fieldCount; i++) - { - if (i > 0) - { - sqlBuilder.Append(", "); - } - - sqlBuilder.Append(":\"" + parameters[i].ParameterName + "\""); - } - - sqlBuilder.AppendLine(")"); - - return (sqlBuilder.ToString(), parameters); - } - - /// - /// Creates a that reads data from the specified sequence of values. - /// - /// The sequence containing the values to be read. - /// The type of values in . - /// A that provides access to the data in . - private static EnumerableReader CreateValuesDataReader( - IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType - ) - { - if (valuesType.IsBuiltInTypeOrNullableBuiltInType() || valuesType.IsEnumOrNullableEnumType()) - { - return new EnumerableReader(values, valuesType, Constants.SingleColumnTemporaryTableColumnName); - } - - return new EnumerableReader( - values, - [.. EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a.CanRead)], - EnumerableReaderOptions.None - ); - } - - /// - /// Drops the temporary table with the specified name. - /// - /// The quoted name of the table to drop. - /// The connection to use to drop the table. - /// The transaction within to drop the table. - private static void DropTemporaryTable( - string quotedTableName, - OracleConnection connection, - OracleTransaction? transaction - ) - { - using var command = connection.CreateCommand(); - - command.CommandText = $"DROP TABLE {quotedTableName}"; - command.Transaction = transaction; - - DbConnectionExtensions.OnBeforeExecutingCommand(command, []); - - command.ExecuteNonQuery(); - } - - /// - /// Asynchronously drops the temporary table with the specified name. - /// - /// The quoted name of the table to drop. - /// The connection to use to drop the table. - /// The transaction within to drop the table. - /// A task representing the asynchronous operation. - private static async ValueTask DropTemporaryTableAsync( - string quotedTableName, - OracleConnection connection, - OracleTransaction? transaction - ) - { -#pragma warning disable CA2007 - await using var command = connection.CreateCommand(); -#pragma warning restore CA2007 - - command.CommandText = $"DROP TABLE {quotedTableName}"; - command.Transaction = transaction; - - DbConnectionExtensions.OnBeforeExecutingCommand(command, []); - - await command.ExecuteNonQueryAsync().ConfigureAwait(false); - } - - private readonly OracleDatabaseAdapter databaseAdapter; } diff --git a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlDatabaseAdapter.cs b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlDatabaseAdapter.cs index 817a105..19c6971 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlDatabaseAdapter.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlDatabaseAdapter.cs @@ -11,6 +11,49 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.PostgreSql; /// public class PostgreSqlDatabaseAdapter : IDatabaseAdapter { + private static readonly Dictionary typeToNpgsqlDbType = new() + { + { typeof(bool), NpgsqlDbType.Boolean }, + { typeof(byte), NpgsqlDbType.Smallint }, + { typeof(byte[]), NpgsqlDbType.Bytea }, + { typeof(char), NpgsqlDbType.Char }, + { typeof(DateOnly), NpgsqlDbType.Date }, + { typeof(DateTime), NpgsqlDbType.Timestamp }, + { typeof(decimal), NpgsqlDbType.Numeric }, + { typeof(double), NpgsqlDbType.Double }, + { typeof(Guid), NpgsqlDbType.Uuid }, + { typeof(short), NpgsqlDbType.Smallint }, + { typeof(int), NpgsqlDbType.Integer }, + { typeof(long), NpgsqlDbType.Bigint }, + { typeof(float), NpgsqlDbType.Real }, + { typeof(string), NpgsqlDbType.Text }, + { typeof(TimeOnly), NpgsqlDbType.Time }, + { typeof(TimeSpan), NpgsqlDbType.Interval }, + }; + + private static readonly Dictionary typeToPostgreSqlDataType = new() + { + { typeof(bool), "boolean" }, + { typeof(byte), "smallint" }, + { typeof(byte[]), "bytea" }, + { typeof(char), "char(1)" }, + { typeof(DateOnly), "date" }, + { typeof(DateTime), "timestamp without time zone" }, + { typeof(decimal), "decimal" }, + { typeof(double), "double precision" }, + { typeof(Guid), "uuid" }, + { typeof(short), "smallint" }, + { typeof(int), "integer" }, + { typeof(long), "bigint" }, + { typeof(float), "real" }, + { typeof(string), "text" }, + { typeof(TimeOnly), "time" }, + { typeof(TimeSpan), "interval" }, + }; + + private readonly PostgreSqlEntityManipulator entityManipulator; + private readonly PostgreSqlTemporaryTableBuilder temporaryTableBuilder; + /// /// Initializes a new instance of the class. /// @@ -178,47 +221,4 @@ public bool WasSqlStatementCancelledByCancellationToken(Exception exception, Can return cancellationToken.IsCancellationRequested && exception is OperationCanceledException; } - - private readonly PostgreSqlEntityManipulator entityManipulator; - private readonly PostgreSqlTemporaryTableBuilder temporaryTableBuilder; - - private static readonly Dictionary typeToNpgsqlDbType = new() - { - { typeof(bool), NpgsqlDbType.Boolean }, - { typeof(byte), NpgsqlDbType.Smallint }, - { typeof(byte[]), NpgsqlDbType.Bytea }, - { typeof(char), NpgsqlDbType.Char }, - { typeof(DateOnly), NpgsqlDbType.Date }, - { typeof(DateTime), NpgsqlDbType.Timestamp }, - { typeof(decimal), NpgsqlDbType.Numeric }, - { typeof(double), NpgsqlDbType.Double }, - { typeof(Guid), NpgsqlDbType.Uuid }, - { typeof(short), NpgsqlDbType.Smallint }, - { typeof(int), NpgsqlDbType.Integer }, - { typeof(long), NpgsqlDbType.Bigint }, - { typeof(float), NpgsqlDbType.Real }, - { typeof(string), NpgsqlDbType.Text }, - { typeof(TimeOnly), NpgsqlDbType.Time }, - { typeof(TimeSpan), NpgsqlDbType.Interval }, - }; - - private static readonly Dictionary typeToPostgreSqlDataType = new() - { - { typeof(bool), "boolean" }, - { typeof(byte), "smallint" }, - { typeof(byte[]), "bytea" }, - { typeof(char), "char(1)" }, - { typeof(DateOnly), "date" }, - { typeof(DateTime), "timestamp without time zone" }, - { typeof(decimal), "decimal" }, - { typeof(double), "double precision" }, - { typeof(Guid), "uuid" }, - { typeof(short), "smallint" }, - { typeof(int), "integer" }, - { typeof(long), "bigint" }, - { typeof(float), "real" }, - { typeof(string), "text" }, - { typeof(TimeOnly), "time" }, - { typeof(TimeSpan), "interval" }, - }; } diff --git a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlEntityManipulator.cs index c8d68d7..92475af 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlEntityManipulator.cs @@ -14,6 +14,11 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.PostgreSql; /// The database adapter to use to manipulate entities. internal class PostgreSqlEntityManipulator(PostgreSqlDatabaseAdapter databaseAdapter) : IEntityManipulator { + private readonly PostgreSqlDatabaseAdapter databaseAdapter = databaseAdapter; + private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); + /// public int DeleteEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, @@ -656,6 +661,81 @@ await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, } } + /// + /// Updates the database generated properties of the provided entity from the provided data reader. + /// + /// The metadata for the entity type. + /// The data reader from which to read the values for the properties. + /// The entity to update. + /// A token that can be used to cancel the operation. + private static void UpdateDatabaseGeneratedProperties( + EntityTypeMetadata entityTypeMetadata, + DbDataReader reader, + object entity, + CancellationToken cancellationToken + ) + { + if (entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 && reader.Read()) + { + cancellationToken.ThrowIfCancellationRequested(); + + for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) + { + var property = entityTypeMetadata.DatabaseGeneratedProperties[i]; + + if (!property.CanWrite) + { + continue; + } + + var value = reader.GetValue(i); + + value = ValueConverter.ConvertValueToType(value, property.PropertyType); + + property.PropertySetter!(entity, value); + } + } + } + + /// + /// Asynchronously updates the database generated properties of the provided entity from the provided data + /// reader. + /// + /// The metadata for the entity type. + /// The data reader from which to read the values for the properties. + /// The entity to update. + /// A token that can be used to cancel the operation. + /// A task that represents the asynchronous operation. + private static async Task UpdateDatabaseGeneratedPropertiesAsync( + EntityTypeMetadata entityTypeMetadata, + DbDataReader reader, + object entity, + CancellationToken cancellationToken + ) + { + if ( + entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 + && await reader.ReadAsync(cancellationToken).ConfigureAwait(false) + ) + { + for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) + { + var property = entityTypeMetadata.DatabaseGeneratedProperties[i]; + + if (!property.CanWrite) + { + continue; + } + + var value = reader.GetValue(i); + + value = ValueConverter.ConvertValueToType(value, property.PropertyType); + + property.PropertySetter!(entity, value); + } + } + } + /// /// Creates a command to delete an entity. /// @@ -1035,84 +1115,4 @@ object entity this.databaseAdapter.BindParameterValue(parameter, propertyValue); } } - - /// - /// Updates the database generated properties of the provided entity from the provided data reader. - /// - /// The metadata for the entity type. - /// The data reader from which to read the values for the properties. - /// The entity to update. - /// A token that can be used to cancel the operation. - private static void UpdateDatabaseGeneratedProperties( - EntityTypeMetadata entityTypeMetadata, - DbDataReader reader, - object entity, - CancellationToken cancellationToken - ) - { - if (entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 && reader.Read()) - { - cancellationToken.ThrowIfCancellationRequested(); - - for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) - { - var property = entityTypeMetadata.DatabaseGeneratedProperties[i]; - - if (!property.CanWrite) - { - continue; - } - - var value = reader.GetValue(i); - - value = ValueConverter.ConvertValueToType(value, property.PropertyType); - - property.PropertySetter!(entity, value); - } - } - } - - /// - /// Asynchronously updates the database generated properties of the provided entity from the provided data - /// reader. - /// - /// The metadata for the entity type. - /// The data reader from which to read the values for the properties. - /// The entity to update. - /// A token that can be used to cancel the operation. - /// A task that represents the asynchronous operation. - private static async Task UpdateDatabaseGeneratedPropertiesAsync( - EntityTypeMetadata entityTypeMetadata, - DbDataReader reader, - object entity, - CancellationToken cancellationToken - ) - { - if ( - entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 - && await reader.ReadAsync(cancellationToken).ConfigureAwait(false) - ) - { - for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) - { - var property = entityTypeMetadata.DatabaseGeneratedProperties[i]; - - if (!property.CanWrite) - { - continue; - } - - var value = reader.GetValue(i); - - value = ValueConverter.ConvertValueToType(value, property.PropertyType); - - property.PropertySetter!(entity, value); - } - } - } - - private readonly PostgreSqlDatabaseAdapter databaseAdapter = databaseAdapter; - private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); - private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); - private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); } diff --git a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlTemporaryTableBuilder.cs b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlTemporaryTableBuilder.cs index 2c22d30..de0644d 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlTemporaryTableBuilder.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlTemporaryTableBuilder.cs @@ -17,6 +17,8 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.PostgreSql; /// internal class PostgreSqlTemporaryTableBuilder : ITemporaryTableBuilder { + private readonly PostgreSqlDatabaseAdapter databaseAdapter; + /// /// Initializes a new instance of the class. /// @@ -192,6 +194,74 @@ await this.PopulateTemporaryTableAsync(npgsqlConnection, name, valuesType, reade ); } + /// + /// Creates a that reads data from the specified sequence of values. + /// + /// The sequence containing the values to be read. + /// The type of values in . + /// + /// A that provides access to the data in . + /// + private static EnumerableReader CreateValuesDataReader( + IEnumerable values, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType + ) + { + if (valuesType.IsBuiltInTypeOrNullableBuiltInType() || valuesType.IsEnumOrNullableEnumType()) + { + return new EnumerableReader(values, valuesType, Constants.SingleColumnTemporaryTableColumnName); + } + + return new EnumerableReader( + values, + [.. EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a.CanRead)], + EnumerableReaderOptions.None + ); + } + + /// + /// Drops the temporary table with the specified name. + /// + /// The name of the table to drop. + /// The connection to use to drop the table. + /// The transaction within to drop the table. + private static void DropTemporaryTable(string name, NpgsqlConnection connection, NpgsqlTransaction? transaction) + { + using var command = connection.CreateCommand(); + + command.CommandText = $"DROP TABLE IF EXISTS \"{name}\""; + command.Transaction = transaction; + + DbConnectionExtensions.OnBeforeExecutingCommand(command, []); + + command.ExecuteNonQuery(); + } + + /// + /// Asynchronously drops the temporary table with the specified name. + /// + /// The name of the table to drop. + /// The connection to use to drop the table. + /// The transaction within to drop the table. + /// A task representing the asynchronous operation. + private static async ValueTask DropTemporaryTableAsync( + string name, + NpgsqlConnection connection, + NpgsqlTransaction? transaction + ) + { +#pragma warning disable CA2007 + await using var command = connection.CreateCommand(); +#pragma warning restore CA2007 + + command.CommandText = $"DROP TABLE IF EXISTS \"{name}\""; + command.Transaction = transaction; + + DbConnectionExtensions.OnBeforeExecutingCommand(command, []); + + await command.ExecuteNonQueryAsync().ConfigureAwait(false); + } + /// /// Builds an SQL code to create a multi-column temporary table to be populated with objects of the type /// . @@ -416,74 +486,4 @@ CancellationToken cancellationToken await importer.CompleteAsync(cancellationToken).ConfigureAwait(false); await importer.CloseAsync(cancellationToken).ConfigureAwait(false); } - - /// - /// Creates a that reads data from the specified sequence of values. - /// - /// The sequence containing the values to be read. - /// The type of values in . - /// - /// A that provides access to the data in . - /// - private static EnumerableReader CreateValuesDataReader( - IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType - ) - { - if (valuesType.IsBuiltInTypeOrNullableBuiltInType() || valuesType.IsEnumOrNullableEnumType()) - { - return new EnumerableReader(values, valuesType, Constants.SingleColumnTemporaryTableColumnName); - } - - return new EnumerableReader( - values, - [.. EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a.CanRead)], - EnumerableReaderOptions.None - ); - } - - /// - /// Drops the temporary table with the specified name. - /// - /// The name of the table to drop. - /// The connection to use to drop the table. - /// The transaction within to drop the table. - private static void DropTemporaryTable(string name, NpgsqlConnection connection, NpgsqlTransaction? transaction) - { - using var command = connection.CreateCommand(); - - command.CommandText = $"DROP TABLE IF EXISTS \"{name}\""; - command.Transaction = transaction; - - DbConnectionExtensions.OnBeforeExecutingCommand(command, []); - - command.ExecuteNonQuery(); - } - - /// - /// Asynchronously drops the temporary table with the specified name. - /// - /// The name of the table to drop. - /// The connection to use to drop the table. - /// The transaction within to drop the table. - /// A task representing the asynchronous operation. - private static async ValueTask DropTemporaryTableAsync( - string name, - NpgsqlConnection connection, - NpgsqlTransaction? transaction - ) - { -#pragma warning disable CA2007 - await using var command = connection.CreateCommand(); -#pragma warning restore CA2007 - - command.CommandText = $"DROP TABLE IF EXISTS \"{name}\""; - command.Transaction = transaction; - - DbConnectionExtensions.OnBeforeExecutingCommand(command, []); - - await command.ExecuteNonQueryAsync().ConfigureAwait(false); - } - - private readonly PostgreSqlDatabaseAdapter databaseAdapter; } diff --git a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerDatabaseAdapter.cs b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerDatabaseAdapter.cs index 611fff7..8a1900c 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerDatabaseAdapter.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerDatabaseAdapter.cs @@ -10,6 +10,31 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.SqlServer; /// public class SqlServerDatabaseAdapter : IDatabaseAdapter { + private static readonly Dictionary typeToSqlDataType = new() + { + { typeof(bool), "bit" }, + { typeof(byte), "tinyint" }, + { typeof(byte[]), "varbinary(max)" }, + { typeof(char), "char(1)" }, + { typeof(DateOnly), "date" }, + { typeof(DateTime), "datetime2" }, + { typeof(DateTimeOffset), "datetimeoffset" }, + { typeof(decimal), "decimal(28,10)" }, + { typeof(double), "float" }, + { typeof(Guid), "uniqueidentifier" }, + { typeof(short), "smallint" }, + { typeof(int), "int" }, + { typeof(long), "bigint" }, + { typeof(object), "sql_variant" }, + { typeof(float), "real" }, + { typeof(string), "nvarchar(max)" }, + { typeof(TimeOnly), "time" }, + { typeof(TimeSpan), "time" }, + }; + + private readonly SqlServerEntityManipulator entityManipulator; + private readonly SqlServerTemporaryTableBuilder temporaryTableBuilder; + /// /// Initializes a new instance of the class. /// @@ -140,29 +165,4 @@ public bool WasSqlStatementCancelledByCancellationToken(Exception exception, Can return false; } - - private readonly SqlServerEntityManipulator entityManipulator; - private readonly SqlServerTemporaryTableBuilder temporaryTableBuilder; - - private static readonly Dictionary typeToSqlDataType = new() - { - { typeof(bool), "bit" }, - { typeof(byte), "tinyint" }, - { typeof(byte[]), "varbinary(max)" }, - { typeof(char), "char(1)" }, - { typeof(DateOnly), "date" }, - { typeof(DateTime), "datetime2" }, - { typeof(DateTimeOffset), "datetimeoffset" }, - { typeof(decimal), "decimal(28,10)" }, - { typeof(double), "float" }, - { typeof(Guid), "uniqueidentifier" }, - { typeof(short), "smallint" }, - { typeof(int), "int" }, - { typeof(long), "bigint" }, - { typeof(object), "sql_variant" }, - { typeof(float), "real" }, - { typeof(string), "nvarchar(max)" }, - { typeof(TimeOnly), "time" }, - { typeof(TimeSpan), "time" }, - }; } diff --git a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerEntityManipulator.cs index e558f6e..905eeaa 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerEntityManipulator.cs @@ -14,6 +14,11 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.SqlServer; /// The database adapter to use to manipulate entities. internal class SqlServerEntityManipulator(SqlServerDatabaseAdapter databaseAdapter) : IEntityManipulator { + private readonly SqlServerDatabaseAdapter databaseAdapter = databaseAdapter; + private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); + /// public int DeleteEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, @@ -656,6 +661,81 @@ await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, } } + /// + /// Updates the database generated properties of the provided entity from the provided data reader. + /// + /// The metadata for the entity type. + /// The data reader from which to read the values for the properties. + /// The entity to update. + /// A token that can be used to cancel the operation. + private static void UpdateDatabaseGeneratedProperties( + EntityTypeMetadata entityTypeMetadata, + DbDataReader reader, + object entity, + CancellationToken cancellationToken + ) + { + if (entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 && reader.Read()) + { + cancellationToken.ThrowIfCancellationRequested(); + + for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) + { + var property = entityTypeMetadata.DatabaseGeneratedProperties[i]; + + if (!property.CanWrite) + { + continue; + } + + var value = reader.GetValue(i); + + value = ValueConverter.ConvertValueToType(value, property.PropertyType); + + property.PropertySetter!(entity, value); + } + } + } + + /// + /// Asynchronously updates the database generated properties of the provided entity from the provided data + /// reader. + /// + /// The metadata for the entity type. + /// The data reader from which to read the values for the properties. + /// The entity to update. + /// A token that can be used to cancel the operation. + /// A task that represents the asynchronous operation. + private static async Task UpdateDatabaseGeneratedPropertiesAsync( + EntityTypeMetadata entityTypeMetadata, + DbDataReader reader, + object entity, + CancellationToken cancellationToken + ) + { + if ( + entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 + && await reader.ReadAsync(cancellationToken).ConfigureAwait(false) + ) + { + for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) + { + var property = entityTypeMetadata.DatabaseGeneratedProperties[i]; + + if (!property.CanWrite) + { + continue; + } + + var value = reader.GetValue(i); + + value = ValueConverter.ConvertValueToType(value, property.PropertyType); + + property.PropertySetter!(entity, value); + } + } + } + /// /// Creates a command to delete an entity. /// @@ -1035,84 +1115,4 @@ object entity this.databaseAdapter.BindParameterValue(parameter, propertyValue); } } - - /// - /// Updates the database generated properties of the provided entity from the provided data reader. - /// - /// The metadata for the entity type. - /// The data reader from which to read the values for the properties. - /// The entity to update. - /// A token that can be used to cancel the operation. - private static void UpdateDatabaseGeneratedProperties( - EntityTypeMetadata entityTypeMetadata, - DbDataReader reader, - object entity, - CancellationToken cancellationToken - ) - { - if (entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 && reader.Read()) - { - cancellationToken.ThrowIfCancellationRequested(); - - for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) - { - var property = entityTypeMetadata.DatabaseGeneratedProperties[i]; - - if (!property.CanWrite) - { - continue; - } - - var value = reader.GetValue(i); - - value = ValueConverter.ConvertValueToType(value, property.PropertyType); - - property.PropertySetter!(entity, value); - } - } - } - - /// - /// Asynchronously updates the database generated properties of the provided entity from the provided data - /// reader. - /// - /// The metadata for the entity type. - /// The data reader from which to read the values for the properties. - /// The entity to update. - /// A token that can be used to cancel the operation. - /// A task that represents the asynchronous operation. - private static async Task UpdateDatabaseGeneratedPropertiesAsync( - EntityTypeMetadata entityTypeMetadata, - DbDataReader reader, - object entity, - CancellationToken cancellationToken - ) - { - if ( - entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 - && await reader.ReadAsync(cancellationToken).ConfigureAwait(false) - ) - { - for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) - { - var property = entityTypeMetadata.DatabaseGeneratedProperties[i]; - - if (!property.CanWrite) - { - continue; - } - - var value = reader.GetValue(i); - - value = ValueConverter.ConvertValueToType(value, property.PropertyType); - - property.PropertySetter!(entity, value); - } - } - } - - private readonly SqlServerDatabaseAdapter databaseAdapter = databaseAdapter; - private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); - private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); - private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); } diff --git a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerTemporaryTableBuilder.cs b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerTemporaryTableBuilder.cs index 1ef68f1..119d1e4 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerTemporaryTableBuilder.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerTemporaryTableBuilder.cs @@ -15,6 +15,16 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.SqlServer; /// internal class SqlServerTemporaryTableBuilder : ITemporaryTableBuilder { + private const string GetCurrentDatabaseCollationQuery = + "SELECT CONVERT (VARCHAR(256), DATABASEPROPERTYEX(DB_NAME(), 'collation'))"; + + private static readonly ConcurrentDictionary< + (string DataSource, string Database), + string + > databaseCollationPerDatabase = []; + + private readonly SqlServerDatabaseAdapter databaseAdapter; + /// /// Initializes a new instance of the class. /// @@ -266,6 +276,129 @@ public async Task BuildTemporaryTableAsync( ); } + /// + /// Creates a that reads data from the specified sequence of values. + /// + /// The sequence containing the values to be read. + /// The type of values in . + /// A that provides access to the data in . + private static EnumerableReader CreateValuesDataReader( + IEnumerable values, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType + ) + { + if (valuesType.IsBuiltInTypeOrNullableBuiltInType() || valuesType.IsEnumOrNullableEnumType()) + { + return new EnumerableReader(values, valuesType, Constants.SingleColumnTemporaryTableColumnName); + } + + return new EnumerableReader( + values, + [.. EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a.CanRead)], + EnumerableReaderOptions.None + ); + } + + /// + /// Drops the temporary table with the specified name. + /// + /// The name of the table to drop. + /// The connection to use to drop the table. + /// The transaction within to drop the table. + private static void DropTemporaryTable(string name, SqlConnection connection, SqlTransaction? transaction) + { + using var command = connection.CreateCommand(); + + command.CommandText = $"IF OBJECT_ID('tempdb..#{name}', 'U') IS NOT NULL DROP TABLE [#{name}]"; + command.Transaction = transaction; + + DbConnectionExtensions.OnBeforeExecutingCommand(command, []); + + command.ExecuteNonQuery(); + } + + /// + /// Asynchronously drops the temporary table with the specified name. + /// + /// The name of the table to drop. + /// The connection to use to drop the table. + /// The transaction within to drop the table. + /// A task representing the asynchronous operation. + private static async ValueTask DropTemporaryTableAsync( + string name, + SqlConnection connection, + SqlTransaction? transaction + ) + { +#pragma warning disable CA2007 + await using var command = connection.CreateCommand(); +#pragma warning restore CA2007 + + command.CommandText = $"IF OBJECT_ID('tempdb..#{name}', 'U') IS NOT NULL DROP TABLE [#{name}]"; + command.Transaction = transaction; + + DbConnectionExtensions.OnBeforeExecutingCommand(command, []); + + await command.ExecuteNonQueryAsync().ConfigureAwait(false); + } + + /// + /// Gets the collation of the database the specified connection is currently connected to. + /// + /// The connection to the database of which to get the collation. + /// The database transaction within to perform the operation. + /// The collation of the database the specified connection is currently connected to. + private static string GetCurrentDatabaseCollation(SqlConnection connection, SqlTransaction? transaction = null) => + databaseCollationPerDatabase.GetOrAdd( + (connection.DataSource, connection.Database), + static (_, args) => + { + using var command = args.connection.CreateCommand(); + + command.CommandText = GetCurrentDatabaseCollationQuery; + command.Transaction = args.transaction; + + DbConnectionExtensions.OnBeforeExecutingCommand(command, []); + + return (string)command.ExecuteScalar()!; + }, + (connection, transaction) + ); + + /// + /// Asynchronously gets the collation of the database the specified connection is currently connected to. + /// + /// The connection to the database of which to get the collation. + /// The database transaction within to perform the operation. + /// + /// A task representing the asynchronous operation. + /// will contain the collation of the database the specified connection is + /// currently connected to. + /// + private static async ValueTask GetCurrentDatabaseCollationAsync( + SqlConnection connection, + SqlTransaction? transaction = null + ) + { + if (databaseCollationPerDatabase.TryGetValue((connection.DataSource, connection.Database), out var collation)) + { + return collation; + } + +#pragma warning disable CA2007 + await using var command = connection.CreateCommand(); +#pragma warning restore CA2007 + + command.CommandText = GetCurrentDatabaseCollationQuery; + command.Transaction = transaction; + + DbConnectionExtensions.OnBeforeExecutingCommand(command, []); + + collation = (string)(await command.ExecuteScalarAsync().ConfigureAwait(false))!; + + return databaseCollationPerDatabase.GetOrAdd((connection.DataSource, connection.Database), collation); + } + /// /// Builds an SQL code to create a multi-column temporary table to be populated with objects of the type /// . @@ -403,137 +536,4 @@ EnumSerializationMode enumSerializationMode return sqlBuilder.ToString(); } - - /// - /// Creates a that reads data from the specified sequence of values. - /// - /// The sequence containing the values to be read. - /// The type of values in . - /// A that provides access to the data in . - private static EnumerableReader CreateValuesDataReader( - IEnumerable values, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType - ) - { - if (valuesType.IsBuiltInTypeOrNullableBuiltInType() || valuesType.IsEnumOrNullableEnumType()) - { - return new EnumerableReader(values, valuesType, Constants.SingleColumnTemporaryTableColumnName); - } - - return new EnumerableReader( - values, - [.. EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a.CanRead)], - EnumerableReaderOptions.None - ); - } - - /// - /// Drops the temporary table with the specified name. - /// - /// The name of the table to drop. - /// The connection to use to drop the table. - /// The transaction within to drop the table. - private static void DropTemporaryTable(string name, SqlConnection connection, SqlTransaction? transaction) - { - using var command = connection.CreateCommand(); - - command.CommandText = $"IF OBJECT_ID('tempdb..#{name}', 'U') IS NOT NULL DROP TABLE [#{name}]"; - command.Transaction = transaction; - - DbConnectionExtensions.OnBeforeExecutingCommand(command, []); - - command.ExecuteNonQuery(); - } - - /// - /// Asynchronously drops the temporary table with the specified name. - /// - /// The name of the table to drop. - /// The connection to use to drop the table. - /// The transaction within to drop the table. - /// A task representing the asynchronous operation. - private static async ValueTask DropTemporaryTableAsync( - string name, - SqlConnection connection, - SqlTransaction? transaction - ) - { -#pragma warning disable CA2007 - await using var command = connection.CreateCommand(); -#pragma warning restore CA2007 - - command.CommandText = $"IF OBJECT_ID('tempdb..#{name}', 'U') IS NOT NULL DROP TABLE [#{name}]"; - command.Transaction = transaction; - - DbConnectionExtensions.OnBeforeExecutingCommand(command, []); - - await command.ExecuteNonQueryAsync().ConfigureAwait(false); - } - - /// - /// Gets the collation of the database the specified connection is currently connected to. - /// - /// The connection to the database of which to get the collation. - /// The database transaction within to perform the operation. - /// The collation of the database the specified connection is currently connected to. - private static string GetCurrentDatabaseCollation(SqlConnection connection, SqlTransaction? transaction = null) => - databaseCollationPerDatabase.GetOrAdd( - (connection.DataSource, connection.Database), - static (_, args) => - { - using var command = args.connection.CreateCommand(); - - command.CommandText = GetCurrentDatabaseCollationQuery; - command.Transaction = args.transaction; - - DbConnectionExtensions.OnBeforeExecutingCommand(command, []); - - return (string)command.ExecuteScalar()!; - }, - (connection, transaction) - ); - - /// - /// Asynchronously gets the collation of the database the specified connection is currently connected to. - /// - /// The connection to the database of which to get the collation. - /// The database transaction within to perform the operation. - /// - /// A task representing the asynchronous operation. - /// will contain the collation of the database the specified connection is - /// currently connected to. - /// - private static async ValueTask GetCurrentDatabaseCollationAsync( - SqlConnection connection, - SqlTransaction? transaction = null - ) - { - if (databaseCollationPerDatabase.TryGetValue((connection.DataSource, connection.Database), out var collation)) - { - return collation; - } - -#pragma warning disable CA2007 - await using var command = connection.CreateCommand(); -#pragma warning restore CA2007 - - command.CommandText = GetCurrentDatabaseCollationQuery; - command.Transaction = transaction; - - DbConnectionExtensions.OnBeforeExecutingCommand(command, []); - - collation = (string)(await command.ExecuteScalarAsync().ConfigureAwait(false))!; - - return databaseCollationPerDatabase.GetOrAdd((connection.DataSource, connection.Database), collation); - } - - private readonly SqlServerDatabaseAdapter databaseAdapter; - - private const string GetCurrentDatabaseCollationQuery = - "SELECT CONVERT (VARCHAR(256), DATABASEPROPERTYEX(DB_NAME(), 'collation'))"; - - private static readonly ConcurrentDictionary< - (string DataSource, string Database), - string - > databaseCollationPerDatabase = []; } diff --git a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteDatabaseAdapter.cs b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteDatabaseAdapter.cs index 40eab80..247210c 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteDatabaseAdapter.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteDatabaseAdapter.cs @@ -10,6 +10,30 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.Sqlite; /// public class SqliteDatabaseAdapter : IDatabaseAdapter { + private static readonly Dictionary typeToSqliteDataType = new() + { + { typeof(bool), "INTEGER" }, + { typeof(byte), "INTEGER" }, + { typeof(byte[]), "BLOB" }, + { typeof(char), "TEXT" }, + { typeof(DateOnly), "TEXT" }, + { typeof(DateTime), "TEXT" }, + { typeof(DateTimeOffset), "TEXT" }, + { typeof(decimal), "TEXT" }, + { typeof(double), "REAL" }, + { typeof(Guid), "TEXT" }, + { typeof(short), "INTEGER" }, + { typeof(int), "INTEGER" }, + { typeof(long), "INTEGER" }, + { typeof(float), "REAL" }, + { typeof(string), "TEXT" }, + { typeof(TimeOnly), "TEXT" }, + { typeof(TimeSpan), "TEXT" }, + }; + + private readonly SqliteEntityManipulator entityManipulator; + private readonly SqliteTemporaryTableBuilder temporaryTableBuilder; + /// /// Initializes a new instance of the class. /// @@ -118,28 +142,4 @@ public bool WasSqlStatementCancelledByCancellationToken(Exception exception, Can // SQLite does not support proper statement cancellation. return false; } - - private readonly SqliteEntityManipulator entityManipulator; - private readonly SqliteTemporaryTableBuilder temporaryTableBuilder; - - private static readonly Dictionary typeToSqliteDataType = new() - { - { typeof(bool), "INTEGER" }, - { typeof(byte), "INTEGER" }, - { typeof(byte[]), "BLOB" }, - { typeof(char), "TEXT" }, - { typeof(DateOnly), "TEXT" }, - { typeof(DateTime), "TEXT" }, - { typeof(DateTimeOffset), "TEXT" }, - { typeof(decimal), "TEXT" }, - { typeof(double), "REAL" }, - { typeof(Guid), "TEXT" }, - { typeof(short), "INTEGER" }, - { typeof(int), "INTEGER" }, - { typeof(long), "INTEGER" }, - { typeof(float), "REAL" }, - { typeof(string), "TEXT" }, - { typeof(TimeOnly), "TEXT" }, - { typeof(TimeSpan), "TEXT" }, - }; } diff --git a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteEntityManipulator.cs index 2e216a1..371db8b 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteEntityManipulator.cs @@ -14,6 +14,11 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.Sqlite; /// The database adapter to use to manipulate entities. internal class SqliteEntityManipulator(SqliteDatabaseAdapter databaseAdapter) : IEntityManipulator { + private readonly SqliteDatabaseAdapter databaseAdapter = databaseAdapter; + private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); + private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); + /// public int DeleteEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( DbConnection connection, @@ -660,6 +665,81 @@ await UpdateDatabaseGeneratedPropertiesAsync(entityTypeMetadata, reader, entity, } } + /// + /// Updates the database generated properties of the provided entity from the provided data reader. + /// + /// The metadata for the entity type. + /// The data reader from which to read the values for the properties. + /// The entity to update. + /// A token that can be used to cancel the operation. + private static void UpdateDatabaseGeneratedProperties( + EntityTypeMetadata entityTypeMetadata, + DbDataReader reader, + object entity, + CancellationToken cancellationToken + ) + { + if (entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 && reader.Read()) + { + cancellationToken.ThrowIfCancellationRequested(); + + for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) + { + var property = entityTypeMetadata.DatabaseGeneratedProperties[i]; + + if (!property.CanWrite) + { + continue; + } + + var value = reader.GetValue(i); + + value = ValueConverter.ConvertValueToType(value, property.PropertyType); + + property.PropertySetter!(entity, value); + } + } + } + + /// + /// Asynchronously updates the database generated properties of the provided entity from the provided data + /// reader. + /// + /// The metadata for the entity type. + /// The data reader from which to read the values for the properties. + /// The entity to update. + /// A token that can be used to cancel the operation. + /// A task that represents the asynchronous operation. + private static async Task UpdateDatabaseGeneratedPropertiesAsync( + EntityTypeMetadata entityTypeMetadata, + DbDataReader reader, + object entity, + CancellationToken cancellationToken + ) + { + if ( + entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 + && await reader.ReadAsync(cancellationToken).ConfigureAwait(false) + ) + { + for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) + { + var property = entityTypeMetadata.DatabaseGeneratedProperties[i]; + + if (!property.CanWrite) + { + continue; + } + + var value = reader.GetValue(i); + + value = ValueConverter.ConvertValueToType(value, property.PropertyType); + + property.PropertySetter!(entity, value); + } + } + } + /// /// Creates a command to delete an entity. /// @@ -1125,84 +1205,4 @@ object entity this.databaseAdapter.BindParameterValue(parameter, propertyValue); } } - - /// - /// Updates the database generated properties of the provided entity from the provided data reader. - /// - /// The metadata for the entity type. - /// The data reader from which to read the values for the properties. - /// The entity to update. - /// A token that can be used to cancel the operation. - private static void UpdateDatabaseGeneratedProperties( - EntityTypeMetadata entityTypeMetadata, - DbDataReader reader, - object entity, - CancellationToken cancellationToken - ) - { - if (entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 && reader.Read()) - { - cancellationToken.ThrowIfCancellationRequested(); - - for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) - { - var property = entityTypeMetadata.DatabaseGeneratedProperties[i]; - - if (!property.CanWrite) - { - continue; - } - - var value = reader.GetValue(i); - - value = ValueConverter.ConvertValueToType(value, property.PropertyType); - - property.PropertySetter!(entity, value); - } - } - } - - /// - /// Asynchronously updates the database generated properties of the provided entity from the provided data - /// reader. - /// - /// The metadata for the entity type. - /// The data reader from which to read the values for the properties. - /// The entity to update. - /// A token that can be used to cancel the operation. - /// A task that represents the asynchronous operation. - private static async Task UpdateDatabaseGeneratedPropertiesAsync( - EntityTypeMetadata entityTypeMetadata, - DbDataReader reader, - object entity, - CancellationToken cancellationToken - ) - { - if ( - entityTypeMetadata.DatabaseGeneratedProperties.Count > 0 - && await reader.ReadAsync(cancellationToken).ConfigureAwait(false) - ) - { - for (var i = 0; i < entityTypeMetadata.DatabaseGeneratedProperties.Count; i++) - { - var property = entityTypeMetadata.DatabaseGeneratedProperties[i]; - - if (!property.CanWrite) - { - continue; - } - - var value = reader.GetValue(i); - - value = ValueConverter.ConvertValueToType(value, property.PropertyType); - - property.PropertySetter!(entity, value); - } - } - } - - private readonly SqliteDatabaseAdapter databaseAdapter = databaseAdapter; - private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); - private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); - private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); } diff --git a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteTemporaryTableBuilder.cs b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteTemporaryTableBuilder.cs index f6d4a30..4880fd6 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteTemporaryTableBuilder.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteTemporaryTableBuilder.cs @@ -16,6 +16,8 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.Sqlite; /// internal class SqliteTemporaryTableBuilder : ITemporaryTableBuilder { + private readonly SqliteDatabaseAdapter databaseAdapter; + /// /// Initializes a new instance of the class. /// @@ -198,86 +200,6 @@ await PopulateTemporaryTableAsync( ); } - /// - /// Builds an SQL code to create a multi-column temporary table to be populated with objects of the type - /// . - /// - /// The name of the table to create. - /// The type of objects with which to populate the table. - /// The mode to use to serialize values. - /// The built SQL code. - private string BuildCreateMultiColumnTemporaryTableSqlCode( - string tableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type objectsType, - EnumSerializationMode enumSerializationMode - ) - { - using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); - - sqlBuilder.Append("CREATE TEMP TABLE \""); - sqlBuilder.Append(tableName); - sqlBuilder.AppendLine("\""); - - sqlBuilder.Append(Constants.Indent); - sqlBuilder.Append("("); - - var properties = EntityHelper.GetEntityTypeMetadata(objectsType).MappedProperties.Where(a => a.CanRead); - - var prependSeparator = false; - - foreach (var property in properties) - { - if (prependSeparator) - { - sqlBuilder.Append(", "); - } - - sqlBuilder.Append('"'); - sqlBuilder.Append(property.ColumnName); - sqlBuilder.Append("\" "); - - var propertyType = property.PropertyType; - - sqlBuilder.Append(this.databaseAdapter.GetDataType(propertyType, enumSerializationMode)); - - prependSeparator = true; - } - - sqlBuilder.AppendLine(")"); - - return sqlBuilder.ToString(); - } - - /// - /// Builds an SQL code to create a single-column temporary table to be populated with values of the type - /// . - /// - /// The name of the table to create. - /// The type of values with which the table will be populated. - /// The mode to use to serialize values. - /// The built SQL code. - private string BuildCreateSingleColumnTemporaryTableSqlCode( - string tableName, - [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, - EnumSerializationMode enumSerializationMode - ) - { - using var sqlBuilder = new ValueStringBuilder(stackalloc char[100]); - - sqlBuilder.Append("CREATE TEMP TABLE \""); - sqlBuilder.Append(tableName); - sqlBuilder.AppendLine("\""); - - sqlBuilder.Append(Constants.Indent); - sqlBuilder.Append("(\""); - sqlBuilder.Append(Constants.SingleColumnTemporaryTableColumnName); - sqlBuilder.Append("\" "); - sqlBuilder.Append(this.databaseAdapter.GetDataType(valuesType, enumSerializationMode)); - sqlBuilder.AppendLine(")"); - - return sqlBuilder.ToString(); - } - /// /// Builds an SQL code to insert data from the specified data reader into the specified temporary table. /// @@ -532,5 +454,83 @@ CancellationToken cancellationToken } } - private readonly SqliteDatabaseAdapter databaseAdapter; + /// + /// Builds an SQL code to create a multi-column temporary table to be populated with objects of the type + /// . + /// + /// The name of the table to create. + /// The type of objects with which to populate the table. + /// The mode to use to serialize values. + /// The built SQL code. + private string BuildCreateMultiColumnTemporaryTableSqlCode( + string tableName, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type objectsType, + EnumSerializationMode enumSerializationMode + ) + { + using var sqlBuilder = new ValueStringBuilder(stackalloc char[500]); + + sqlBuilder.Append("CREATE TEMP TABLE \""); + sqlBuilder.Append(tableName); + sqlBuilder.AppendLine("\""); + + sqlBuilder.Append(Constants.Indent); + sqlBuilder.Append("("); + + var properties = EntityHelper.GetEntityTypeMetadata(objectsType).MappedProperties.Where(a => a.CanRead); + + var prependSeparator = false; + + foreach (var property in properties) + { + if (prependSeparator) + { + sqlBuilder.Append(", "); + } + + sqlBuilder.Append('"'); + sqlBuilder.Append(property.ColumnName); + sqlBuilder.Append("\" "); + + var propertyType = property.PropertyType; + + sqlBuilder.Append(this.databaseAdapter.GetDataType(propertyType, enumSerializationMode)); + + prependSeparator = true; + } + + sqlBuilder.AppendLine(")"); + + return sqlBuilder.ToString(); + } + + /// + /// Builds an SQL code to create a single-column temporary table to be populated with values of the type + /// . + /// + /// The name of the table to create. + /// The type of values with which the table will be populated. + /// The mode to use to serialize values. + /// The built SQL code. + private string BuildCreateSingleColumnTemporaryTableSqlCode( + string tableName, + [DynamicallyAccessedMembers(EntityHelper.TemporaryTableValueMemberTypes)] Type valuesType, + EnumSerializationMode enumSerializationMode + ) + { + using var sqlBuilder = new ValueStringBuilder(stackalloc char[100]); + + sqlBuilder.Append("CREATE TEMP TABLE \""); + sqlBuilder.Append(tableName); + sqlBuilder.AppendLine("\""); + + sqlBuilder.Append(Constants.Indent); + sqlBuilder.Append("(\""); + sqlBuilder.Append(Constants.SingleColumnTemporaryTableColumnName); + sqlBuilder.Append("\" "); + sqlBuilder.Append(this.databaseAdapter.GetDataType(valuesType, enumSerializationMode)); + sqlBuilder.AppendLine(")"); + + return sqlBuilder.ToString(); + } } diff --git a/src/DbConnectionPlus/Configuration/DbConnectionPlusConfiguration.cs b/src/DbConnectionPlus/Configuration/DbConnectionPlusConfiguration.cs index 609fa7b..dc170b8 100644 --- a/src/DbConnectionPlus/Configuration/DbConnectionPlusConfiguration.cs +++ b/src/DbConnectionPlus/Configuration/DbConnectionPlusConfiguration.cs @@ -5,11 +5,20 @@ namespace RentADeveloper.DbConnectionPlus.Configuration; /// public sealed class DbConnectionPlusConfiguration : IFreezable { + private readonly Dictionary databaseAdapters = []; + private readonly Dictionary entityTypeBuilders = []; + private bool isFrozen; + /// /// Initializes a new instance of the class. /// internal DbConnectionPlusConfiguration() { } + /// + /// The singleton instance of . + /// + public static DbConnectionPlusConfiguration Instance { get; internal set; } = new(); + /// /// /// Controls how values are serialized when they are sent to a database using one of the @@ -117,22 +126,6 @@ public void RegisterDatabaseAdapter(IDatabaseAdapter adapter) this.databaseAdapters[typeof(TConnection)] = adapter; } - /// - void IFreezable.Freeze() - { - this.isFrozen = true; - - foreach (var entityTypeBuilder in this.entityTypeBuilders.Values) - { - entityTypeBuilder.Freeze(); - } - } - - /// - /// The singleton instance of . - /// - public static DbConnectionPlusConfiguration Instance { get; internal set; } = new(); - /// /// Retrieves the database adapter associated with the connection type . /// @@ -182,7 +175,14 @@ private void EnsureNotFrozen() } } - private readonly Dictionary databaseAdapters = []; - private readonly Dictionary entityTypeBuilders = []; - private bool isFrozen; + /// + void IFreezable.Freeze() + { + this.isFrozen = true; + + foreach (var entityTypeBuilder in this.entityTypeBuilders.Values) + { + entityTypeBuilder.Freeze(); + } + } } diff --git a/src/DbConnectionPlus/Configuration/EntityPropertyBuilder.cs b/src/DbConnectionPlus/Configuration/EntityPropertyBuilder.cs index e262293..04a5c34 100644 --- a/src/DbConnectionPlus/Configuration/EntityPropertyBuilder.cs +++ b/src/DbConnectionPlus/Configuration/EntityPropertyBuilder.cs @@ -5,6 +5,18 @@ namespace RentADeveloper.DbConnectionPlus.Configuration; /// public sealed class EntityPropertyBuilder : IEntityPropertyBuilder { + private readonly IEntityTypeBuilder entityTypeBuilder; + private readonly string propertyName; + + private string? columnName; + private bool isComputed; + private bool isConcurrencyToken; + private bool isFrozen; + private bool isIdentity; + private bool isIgnored; + private bool isKey; + private bool isRowVersion; + /// /// Initializes a new instance of the class. /// @@ -34,6 +46,30 @@ internal EntityPropertyBuilder(IEntityTypeBuilder entityTypeBuilder, string prop this.propertyName = propertyName; } + /// + string? IEntityPropertyBuilder.ColumnName => this.columnName; + + /// + bool IEntityPropertyBuilder.IsComputed => this.isComputed; + + /// + bool IEntityPropertyBuilder.IsConcurrencyToken => this.isConcurrencyToken; + + /// + bool IEntityPropertyBuilder.IsIdentity => this.isIdentity; + + /// + bool IEntityPropertyBuilder.IsIgnored => this.isIgnored; + + /// + bool IEntityPropertyBuilder.IsKey => this.isKey; + + /// + bool IEntityPropertyBuilder.IsRowVersion => this.isRowVersion; + + /// + string IEntityPropertyBuilder.PropertyName => this.propertyName; + /// /// Sets the name of the column to map the property to. /// @@ -166,33 +202,6 @@ public EntityPropertyBuilder IsRowVersion() return this; } - /// - string? IEntityPropertyBuilder.ColumnName => this.columnName; - - /// - void IFreezable.Freeze() => this.isFrozen = true; - - /// - bool IEntityPropertyBuilder.IsComputed => this.isComputed; - - /// - bool IEntityPropertyBuilder.IsConcurrencyToken => this.isConcurrencyToken; - - /// - bool IEntityPropertyBuilder.IsIdentity => this.isIdentity; - - /// - bool IEntityPropertyBuilder.IsIgnored => this.isIgnored; - - /// - bool IEntityPropertyBuilder.IsKey => this.isKey; - - /// - bool IEntityPropertyBuilder.IsRowVersion => this.isRowVersion; - - /// - string IEntityPropertyBuilder.PropertyName => this.propertyName; - /// /// Ensures this instance is not frozen. /// @@ -205,15 +214,6 @@ private void EnsureNotFrozen() } } - private readonly IEntityTypeBuilder entityTypeBuilder; - private readonly string propertyName; - - private string? columnName; - private bool isComputed; - private bool isConcurrencyToken; - private bool isFrozen; - private bool isIdentity; - private bool isIgnored; - private bool isKey; - private bool isRowVersion; + /// + void IFreezable.Freeze() => this.isFrozen = true; } diff --git a/src/DbConnectionPlus/Configuration/EntityTypeBuilder.cs b/src/DbConnectionPlus/Configuration/EntityTypeBuilder.cs index e9ff601..13bb76f 100644 --- a/src/DbConnectionPlus/Configuration/EntityTypeBuilder.cs +++ b/src/DbConnectionPlus/Configuration/EntityTypeBuilder.cs @@ -9,6 +9,19 @@ namespace RentADeveloper.DbConnectionPlus.Configuration; /// The type of the entity being configured. public sealed class EntityTypeBuilder : IEntityTypeBuilder { + private readonly ConcurrentDictionary propertyBuilders = new(); + private bool isFrozen; + private string? tableName; + + /// + Type IEntityTypeBuilder.EntityType => typeof(TEntity); + + /// + IReadOnlyDictionary IEntityTypeBuilder.PropertyBuilders => this.propertyBuilders; + + /// + string? IEntityTypeBuilder.TableName => this.tableName; + /// /// Gets a builder for configuring the specified property. /// @@ -60,38 +73,6 @@ public EntityTypeBuilder ToTable(string tableName) return this; } - /// - Type IEntityTypeBuilder.EntityType => typeof(TEntity); - - /// - void IFreezable.Freeze() - { - this.isFrozen = true; - - foreach (var propertyBuilder in this.propertyBuilders.Values) - { - propertyBuilder.Freeze(); - } - } - - /// - IReadOnlyDictionary IEntityTypeBuilder.PropertyBuilders => this.propertyBuilders; - - /// - string? IEntityTypeBuilder.TableName => this.tableName; - - /// - /// Ensures this instance is not frozen. - /// - /// This object is already frozen. - private void EnsureNotFrozen() - { - if (this.isFrozen) - { - ThrowHelper.ThrowConfigurationIsFrozenException(); - } - } - /// /// Gets the name of the property accessed in the specified property access expression. /// @@ -109,7 +90,26 @@ private static string GetPropertyNameFromPropertyExpression(LambdaExpression pro nameof(propertyExpression) ); - private readonly ConcurrentDictionary propertyBuilders = new(); - private bool isFrozen; - private string? tableName; + /// + /// Ensures this instance is not frozen. + /// + /// This object is already frozen. + private void EnsureNotFrozen() + { + if (this.isFrozen) + { + ThrowHelper.ThrowConfigurationIsFrozenException(); + } + } + + /// + void IFreezable.Freeze() + { + this.isFrozen = true; + + foreach (var propertyBuilder in this.propertyBuilders.Values) + { + propertyBuilder.Freeze(); + } + } } diff --git a/src/DbConnectionPlus/Converters/ValueConverter.cs b/src/DbConnectionPlus/Converters/ValueConverter.cs index c1b9dc1..03389d1 100644 --- a/src/DbConnectionPlus/Converters/ValueConverter.cs +++ b/src/DbConnectionPlus/Converters/ValueConverter.cs @@ -11,6 +11,222 @@ namespace RentADeveloper.DbConnectionPlus.Converters; /// internal static class ValueConverter { + private static readonly HashSet<(Type SourceType, Type TargetType)> supportedConversions = + [ + (typeof(bool), typeof(bool)), + (typeof(bool), typeof(byte)), + (typeof(bool), typeof(decimal)), + (typeof(bool), typeof(double)), + (typeof(bool), typeof(short)), + (typeof(bool), typeof(int)), + (typeof(bool), typeof(long)), + (typeof(bool), typeof(sbyte)), + (typeof(bool), typeof(float)), + (typeof(bool), typeof(string)), + (typeof(bool), typeof(ushort)), + (typeof(bool), typeof(uint)), + (typeof(bool), typeof(ulong)), + (typeof(byte), typeof(bool)), + (typeof(byte), typeof(byte)), + (typeof(byte), typeof(char)), + (typeof(byte), typeof(decimal)), + (typeof(byte), typeof(double)), + (typeof(byte), typeof(short)), + (typeof(byte), typeof(int)), + (typeof(byte), typeof(long)), + (typeof(byte), typeof(sbyte)), + (typeof(byte), typeof(float)), + (typeof(byte), typeof(string)), + (typeof(byte), typeof(ushort)), + (typeof(byte), typeof(uint)), + (typeof(byte), typeof(ulong)), + (typeof(byte[]), typeof(Guid)), + (typeof(char), typeof(byte)), + (typeof(char), typeof(char)), + (typeof(char), typeof(short)), + (typeof(char), typeof(int)), + (typeof(char), typeof(long)), + (typeof(char), typeof(sbyte)), + (typeof(char), typeof(string)), + (typeof(char), typeof(ushort)), + (typeof(char), typeof(uint)), + (typeof(char), typeof(ulong)), + (typeof(DateOnly), typeof(DateOnly)), + (typeof(DateOnly), typeof(string)), + (typeof(DateTime), typeof(DateTime)), + (typeof(DateTime), typeof(DateOnly)), + (typeof(DateTime), typeof(string)), + (typeof(DateTimeOffset), typeof(DateTimeOffset)), + (typeof(DateTimeOffset), typeof(string)), + (typeof(decimal), typeof(bool)), + (typeof(decimal), typeof(byte)), + (typeof(decimal), typeof(decimal)), + (typeof(decimal), typeof(double)), + (typeof(decimal), typeof(short)), + (typeof(decimal), typeof(int)), + (typeof(decimal), typeof(long)), + (typeof(decimal), typeof(sbyte)), + (typeof(decimal), typeof(float)), + (typeof(decimal), typeof(string)), + (typeof(decimal), typeof(ushort)), + (typeof(decimal), typeof(uint)), + (typeof(decimal), typeof(ulong)), + (typeof(double), typeof(bool)), + (typeof(double), typeof(byte)), + (typeof(double), typeof(decimal)), + (typeof(double), typeof(double)), + (typeof(double), typeof(short)), + (typeof(double), typeof(int)), + (typeof(double), typeof(long)), + (typeof(double), typeof(sbyte)), + (typeof(double), typeof(float)), + (typeof(double), typeof(string)), + (typeof(double), typeof(ushort)), + (typeof(double), typeof(uint)), + (typeof(double), typeof(ulong)), + (typeof(Guid), typeof(byte[])), + (typeof(Guid), typeof(Guid)), + (typeof(Guid), typeof(string)), + (typeof(short), typeof(bool)), + (typeof(short), typeof(byte)), + (typeof(short), typeof(char)), + (typeof(short), typeof(decimal)), + (typeof(short), typeof(double)), + (typeof(short), typeof(short)), + (typeof(short), typeof(int)), + (typeof(short), typeof(long)), + (typeof(short), typeof(sbyte)), + (typeof(short), typeof(float)), + (typeof(short), typeof(string)), + (typeof(short), typeof(ushort)), + (typeof(short), typeof(uint)), + (typeof(short), typeof(ulong)), + (typeof(int), typeof(bool)), + (typeof(int), typeof(byte)), + (typeof(int), typeof(char)), + (typeof(int), typeof(decimal)), + (typeof(int), typeof(double)), + (typeof(int), typeof(short)), + (typeof(int), typeof(int)), + (typeof(int), typeof(long)), + (typeof(int), typeof(sbyte)), + (typeof(int), typeof(float)), + (typeof(int), typeof(string)), + (typeof(int), typeof(ushort)), + (typeof(int), typeof(uint)), + (typeof(int), typeof(ulong)), + (typeof(long), typeof(bool)), + (typeof(long), typeof(byte)), + (typeof(long), typeof(char)), + (typeof(long), typeof(decimal)), + (typeof(long), typeof(double)), + (typeof(long), typeof(short)), + (typeof(long), typeof(int)), + (typeof(long), typeof(long)), + (typeof(long), typeof(sbyte)), + (typeof(long), typeof(float)), + (typeof(long), typeof(string)), + (typeof(long), typeof(ushort)), + (typeof(long), typeof(uint)), + (typeof(long), typeof(ulong)), + (typeof(IntPtr), typeof(IntPtr)), + (typeof(sbyte), typeof(bool)), + (typeof(sbyte), typeof(byte)), + (typeof(sbyte), typeof(char)), + (typeof(sbyte), typeof(decimal)), + (typeof(sbyte), typeof(double)), + (typeof(sbyte), typeof(short)), + (typeof(sbyte), typeof(int)), + (typeof(sbyte), typeof(long)), + (typeof(sbyte), typeof(sbyte)), + (typeof(sbyte), typeof(float)), + (typeof(sbyte), typeof(string)), + (typeof(sbyte), typeof(ushort)), + (typeof(sbyte), typeof(uint)), + (typeof(sbyte), typeof(ulong)), + (typeof(float), typeof(bool)), + (typeof(float), typeof(byte)), + (typeof(float), typeof(decimal)), + (typeof(float), typeof(double)), + (typeof(float), typeof(short)), + (typeof(float), typeof(int)), + (typeof(float), typeof(long)), + (typeof(float), typeof(sbyte)), + (typeof(float), typeof(float)), + (typeof(float), typeof(string)), + (typeof(float), typeof(ushort)), + (typeof(float), typeof(uint)), + (typeof(float), typeof(ulong)), + (typeof(string), typeof(bool)), + (typeof(string), typeof(byte)), + (typeof(string), typeof(char)), + (typeof(string), typeof(DateTime)), + (typeof(string), typeof(DateTimeOffset)), + (typeof(string), typeof(DateOnly)), + (typeof(string), typeof(decimal)), + (typeof(string), typeof(double)), + (typeof(string), typeof(Guid)), + (typeof(string), typeof(short)), + (typeof(string), typeof(int)), + (typeof(string), typeof(long)), + (typeof(string), typeof(sbyte)), + (typeof(string), typeof(float)), + (typeof(string), typeof(string)), + (typeof(string), typeof(ushort)), + (typeof(string), typeof(uint)), + (typeof(string), typeof(ulong)), + (typeof(string), typeof(TimeSpan)), + (typeof(string), typeof(TimeOnly)), + (typeof(TimeOnly), typeof(TimeOnly)), + (typeof(TimeOnly), typeof(string)), + (typeof(TimeSpan), typeof(TimeOnly)), + (typeof(TimeSpan), typeof(TimeSpan)), + (typeof(TimeSpan), typeof(string)), + (typeof(ushort), typeof(bool)), + (typeof(ushort), typeof(byte)), + (typeof(ushort), typeof(char)), + (typeof(ushort), typeof(decimal)), + (typeof(ushort), typeof(double)), + (typeof(ushort), typeof(short)), + (typeof(ushort), typeof(int)), + (typeof(ushort), typeof(long)), + (typeof(ushort), typeof(sbyte)), + (typeof(ushort), typeof(float)), + (typeof(ushort), typeof(string)), + (typeof(ushort), typeof(ushort)), + (typeof(ushort), typeof(uint)), + (typeof(ushort), typeof(ulong)), + (typeof(uint), typeof(bool)), + (typeof(uint), typeof(byte)), + (typeof(uint), typeof(char)), + (typeof(uint), typeof(decimal)), + (typeof(uint), typeof(double)), + (typeof(uint), typeof(short)), + (typeof(uint), typeof(int)), + (typeof(uint), typeof(long)), + (typeof(uint), typeof(sbyte)), + (typeof(uint), typeof(float)), + (typeof(uint), typeof(string)), + (typeof(uint), typeof(ushort)), + (typeof(uint), typeof(uint)), + (typeof(uint), typeof(ulong)), + (typeof(ulong), typeof(bool)), + (typeof(ulong), typeof(byte)), + (typeof(ulong), typeof(char)), + (typeof(ulong), typeof(decimal)), + (typeof(ulong), typeof(double)), + (typeof(ulong), typeof(short)), + (typeof(ulong), typeof(int)), + (typeof(ulong), typeof(long)), + (typeof(ulong), typeof(sbyte)), + (typeof(ulong), typeof(float)), + (typeof(ulong), typeof(string)), + (typeof(ulong), typeof(ushort)), + (typeof(ulong), typeof(uint)), + (typeof(ulong), typeof(ulong)), + (typeof(UIntPtr), typeof(UIntPtr)), + ]; + /// /// Determines whether this converter can convert a value of the type to the type /// . @@ -425,220 +641,4 @@ private static void ThrowCouldNotConvertValueToTargetTypeException(object? value throw new InvalidCastException( $"Could not convert the value {value.ToDebugString()} to the type {targetType}. " ); - - private static readonly HashSet<(Type SourceType, Type TargetType)> supportedConversions = - [ - (typeof(bool), typeof(bool)), - (typeof(bool), typeof(byte)), - (typeof(bool), typeof(decimal)), - (typeof(bool), typeof(double)), - (typeof(bool), typeof(short)), - (typeof(bool), typeof(int)), - (typeof(bool), typeof(long)), - (typeof(bool), typeof(sbyte)), - (typeof(bool), typeof(float)), - (typeof(bool), typeof(string)), - (typeof(bool), typeof(ushort)), - (typeof(bool), typeof(uint)), - (typeof(bool), typeof(ulong)), - (typeof(byte), typeof(bool)), - (typeof(byte), typeof(byte)), - (typeof(byte), typeof(char)), - (typeof(byte), typeof(decimal)), - (typeof(byte), typeof(double)), - (typeof(byte), typeof(short)), - (typeof(byte), typeof(int)), - (typeof(byte), typeof(long)), - (typeof(byte), typeof(sbyte)), - (typeof(byte), typeof(float)), - (typeof(byte), typeof(string)), - (typeof(byte), typeof(ushort)), - (typeof(byte), typeof(uint)), - (typeof(byte), typeof(ulong)), - (typeof(byte[]), typeof(Guid)), - (typeof(char), typeof(byte)), - (typeof(char), typeof(char)), - (typeof(char), typeof(short)), - (typeof(char), typeof(int)), - (typeof(char), typeof(long)), - (typeof(char), typeof(sbyte)), - (typeof(char), typeof(string)), - (typeof(char), typeof(ushort)), - (typeof(char), typeof(uint)), - (typeof(char), typeof(ulong)), - (typeof(DateOnly), typeof(DateOnly)), - (typeof(DateOnly), typeof(string)), - (typeof(DateTime), typeof(DateTime)), - (typeof(DateTime), typeof(DateOnly)), - (typeof(DateTime), typeof(string)), - (typeof(DateTimeOffset), typeof(DateTimeOffset)), - (typeof(DateTimeOffset), typeof(string)), - (typeof(decimal), typeof(bool)), - (typeof(decimal), typeof(byte)), - (typeof(decimal), typeof(decimal)), - (typeof(decimal), typeof(double)), - (typeof(decimal), typeof(short)), - (typeof(decimal), typeof(int)), - (typeof(decimal), typeof(long)), - (typeof(decimal), typeof(sbyte)), - (typeof(decimal), typeof(float)), - (typeof(decimal), typeof(string)), - (typeof(decimal), typeof(ushort)), - (typeof(decimal), typeof(uint)), - (typeof(decimal), typeof(ulong)), - (typeof(double), typeof(bool)), - (typeof(double), typeof(byte)), - (typeof(double), typeof(decimal)), - (typeof(double), typeof(double)), - (typeof(double), typeof(short)), - (typeof(double), typeof(int)), - (typeof(double), typeof(long)), - (typeof(double), typeof(sbyte)), - (typeof(double), typeof(float)), - (typeof(double), typeof(string)), - (typeof(double), typeof(ushort)), - (typeof(double), typeof(uint)), - (typeof(double), typeof(ulong)), - (typeof(Guid), typeof(byte[])), - (typeof(Guid), typeof(Guid)), - (typeof(Guid), typeof(string)), - (typeof(short), typeof(bool)), - (typeof(short), typeof(byte)), - (typeof(short), typeof(char)), - (typeof(short), typeof(decimal)), - (typeof(short), typeof(double)), - (typeof(short), typeof(short)), - (typeof(short), typeof(int)), - (typeof(short), typeof(long)), - (typeof(short), typeof(sbyte)), - (typeof(short), typeof(float)), - (typeof(short), typeof(string)), - (typeof(short), typeof(ushort)), - (typeof(short), typeof(uint)), - (typeof(short), typeof(ulong)), - (typeof(int), typeof(bool)), - (typeof(int), typeof(byte)), - (typeof(int), typeof(char)), - (typeof(int), typeof(decimal)), - (typeof(int), typeof(double)), - (typeof(int), typeof(short)), - (typeof(int), typeof(int)), - (typeof(int), typeof(long)), - (typeof(int), typeof(sbyte)), - (typeof(int), typeof(float)), - (typeof(int), typeof(string)), - (typeof(int), typeof(ushort)), - (typeof(int), typeof(uint)), - (typeof(int), typeof(ulong)), - (typeof(long), typeof(bool)), - (typeof(long), typeof(byte)), - (typeof(long), typeof(char)), - (typeof(long), typeof(decimal)), - (typeof(long), typeof(double)), - (typeof(long), typeof(short)), - (typeof(long), typeof(int)), - (typeof(long), typeof(long)), - (typeof(long), typeof(sbyte)), - (typeof(long), typeof(float)), - (typeof(long), typeof(string)), - (typeof(long), typeof(ushort)), - (typeof(long), typeof(uint)), - (typeof(long), typeof(ulong)), - (typeof(IntPtr), typeof(IntPtr)), - (typeof(sbyte), typeof(bool)), - (typeof(sbyte), typeof(byte)), - (typeof(sbyte), typeof(char)), - (typeof(sbyte), typeof(decimal)), - (typeof(sbyte), typeof(double)), - (typeof(sbyte), typeof(short)), - (typeof(sbyte), typeof(int)), - (typeof(sbyte), typeof(long)), - (typeof(sbyte), typeof(sbyte)), - (typeof(sbyte), typeof(float)), - (typeof(sbyte), typeof(string)), - (typeof(sbyte), typeof(ushort)), - (typeof(sbyte), typeof(uint)), - (typeof(sbyte), typeof(ulong)), - (typeof(float), typeof(bool)), - (typeof(float), typeof(byte)), - (typeof(float), typeof(decimal)), - (typeof(float), typeof(double)), - (typeof(float), typeof(short)), - (typeof(float), typeof(int)), - (typeof(float), typeof(long)), - (typeof(float), typeof(sbyte)), - (typeof(float), typeof(float)), - (typeof(float), typeof(string)), - (typeof(float), typeof(ushort)), - (typeof(float), typeof(uint)), - (typeof(float), typeof(ulong)), - (typeof(string), typeof(bool)), - (typeof(string), typeof(byte)), - (typeof(string), typeof(char)), - (typeof(string), typeof(DateTime)), - (typeof(string), typeof(DateTimeOffset)), - (typeof(string), typeof(DateOnly)), - (typeof(string), typeof(decimal)), - (typeof(string), typeof(double)), - (typeof(string), typeof(Guid)), - (typeof(string), typeof(short)), - (typeof(string), typeof(int)), - (typeof(string), typeof(long)), - (typeof(string), typeof(sbyte)), - (typeof(string), typeof(float)), - (typeof(string), typeof(string)), - (typeof(string), typeof(ushort)), - (typeof(string), typeof(uint)), - (typeof(string), typeof(ulong)), - (typeof(string), typeof(TimeSpan)), - (typeof(string), typeof(TimeOnly)), - (typeof(TimeOnly), typeof(TimeOnly)), - (typeof(TimeOnly), typeof(string)), - (typeof(TimeSpan), typeof(TimeOnly)), - (typeof(TimeSpan), typeof(TimeSpan)), - (typeof(TimeSpan), typeof(string)), - (typeof(ushort), typeof(bool)), - (typeof(ushort), typeof(byte)), - (typeof(ushort), typeof(char)), - (typeof(ushort), typeof(decimal)), - (typeof(ushort), typeof(double)), - (typeof(ushort), typeof(short)), - (typeof(ushort), typeof(int)), - (typeof(ushort), typeof(long)), - (typeof(ushort), typeof(sbyte)), - (typeof(ushort), typeof(float)), - (typeof(ushort), typeof(string)), - (typeof(ushort), typeof(ushort)), - (typeof(ushort), typeof(uint)), - (typeof(ushort), typeof(ulong)), - (typeof(uint), typeof(bool)), - (typeof(uint), typeof(byte)), - (typeof(uint), typeof(char)), - (typeof(uint), typeof(decimal)), - (typeof(uint), typeof(double)), - (typeof(uint), typeof(short)), - (typeof(uint), typeof(int)), - (typeof(uint), typeof(long)), - (typeof(uint), typeof(sbyte)), - (typeof(uint), typeof(float)), - (typeof(uint), typeof(string)), - (typeof(uint), typeof(ushort)), - (typeof(uint), typeof(uint)), - (typeof(uint), typeof(ulong)), - (typeof(ulong), typeof(bool)), - (typeof(ulong), typeof(byte)), - (typeof(ulong), typeof(char)), - (typeof(ulong), typeof(decimal)), - (typeof(ulong), typeof(double)), - (typeof(ulong), typeof(short)), - (typeof(ulong), typeof(int)), - (typeof(ulong), typeof(long)), - (typeof(ulong), typeof(sbyte)), - (typeof(ulong), typeof(float)), - (typeof(ulong), typeof(string)), - (typeof(ulong), typeof(ushort)), - (typeof(ulong), typeof(uint)), - (typeof(ulong), typeof(ulong)), - (typeof(UIntPtr), typeof(UIntPtr)), - ]; } diff --git a/src/DbConnectionPlus/DatabaseAdapters/TemporaryTableDisposer.cs b/src/DbConnectionPlus/DatabaseAdapters/TemporaryTableDisposer.cs index 6a32a63..3612e69 100644 --- a/src/DbConnectionPlus/DatabaseAdapters/TemporaryTableDisposer.cs +++ b/src/DbConnectionPlus/DatabaseAdapters/TemporaryTableDisposer.cs @@ -9,6 +9,11 @@ namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters; /// public sealed class TemporaryTableDisposer : IDisposable, IAsyncDisposable { + private readonly Func dropTableAsyncFunction; + private readonly Action dropTableFunction; + + private bool isDisposed; + /// /// Initializes a new instance of the class. /// @@ -65,9 +70,4 @@ public ValueTask DisposeAsync() this.isDisposed = true; return this.dropTableAsyncFunction(); } - - private readonly Func dropTableAsyncFunction; - private readonly Action dropTableFunction; - - private bool isDisposed; } diff --git a/src/DbConnectionPlus/DbCommands/DbCommandDisposer.cs b/src/DbConnectionPlus/DbCommands/DbCommandDisposer.cs index 03db21a..aaa802a 100644 --- a/src/DbConnectionPlus/DbCommands/DbCommandDisposer.cs +++ b/src/DbConnectionPlus/DbCommands/DbCommandDisposer.cs @@ -10,6 +10,12 @@ namespace RentADeveloper.DbConnectionPlus.DbCommands; /// internal class DbCommandDisposer : IDisposable, IAsyncDisposable { + private readonly CancellationTokenRegistration cancellationTokenRegistration; + private readonly DbCommand command; + private readonly TemporaryTableDisposer[] temporaryTableDisposers; + + private bool isDisposed; + /// /// Initializes a new instance of the class. /// @@ -90,10 +96,4 @@ public async ValueTask DisposeAsync() await tableDisposer.DisposeAsync().ConfigureAwait(false); } } - - private readonly CancellationTokenRegistration cancellationTokenRegistration; - private readonly DbCommand command; - private readonly TemporaryTableDisposer[] temporaryTableDisposers; - - private bool isDisposed; } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.Configuration.cs b/src/DbConnectionPlus/DbConnectionExtensions.Configuration.cs index ccf9468..50093a8 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.Configuration.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.Configuration.cs @@ -11,6 +11,8 @@ namespace RentADeveloper.DbConnectionPlus; /// public static partial class DbConnectionExtensions { + private static readonly object configurationLockObject = new(); + /// /// Configures DbConnectionPlus. /// @@ -45,6 +47,4 @@ internal static void OnBeforeExecutingCommand( DbCommand command, IReadOnlyList temporaryTables ) => DbConnectionPlusConfiguration.Instance.InterceptDbCommand?.Invoke(command, temporaryTables); - - private static readonly object configurationLockObject = new(); } diff --git a/src/DbConnectionPlus/DbConnectionExtensions.Parameter.cs b/src/DbConnectionPlus/DbConnectionExtensions.Parameter.cs index d45c7d6..0a9ba20 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.Parameter.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.Parameter.cs @@ -11,6 +11,11 @@ namespace RentADeveloper.DbConnectionPlus; /// public static partial class DbConnectionExtensions { + /// + /// The maximum length for inferred parameter names. This length is supported by all major database systems. + /// + private const int MaximumParameterNameLength = 60; + /// /// /// Wraps in an instance of to indicate @@ -87,9 +92,4 @@ public static InterpolatedParameter Parameter( return new(inferredParameterName, parameterValue); } - - /// - /// The maximum length for inferred parameter names. This length is supported by all major database systems. - /// - private const int MaximumParameterNameLength = 60; } diff --git a/src/DbConnectionPlus/Dynamic/DataRow.cs b/src/DbConnectionPlus/Dynamic/DataRow.cs index 71f69e4..8bada07 100644 --- a/src/DbConnectionPlus/Dynamic/DataRow.cs +++ b/src/DbConnectionPlus/Dynamic/DataRow.cs @@ -47,12 +47,31 @@ namespace RentADeveloper.DbConnectionPlus.Dynamic; public class DataRow(IDictionary columns) : IDictionary, IDynamicMetaObjectProvider #pragma warning restore CA1710 { + /// + /// Reads the value of a column, used as the target of a bound dynamic member read. + /// + private static readonly Func readColumn = static (row, columnName) => row[columnName]; + + /// + /// Writes the value of a column and returns it, used as the target of a bound dynamic member write. + /// + private static readonly Func writeColumn = static (row, columnName, value) => + row[columnName] = value; + + private readonly IDictionary columns = columns; + /// public int Count => this.columns.Count; /// public bool IsReadOnly => this.columns.IsReadOnly; + /// + public ICollection Keys => this.columns.Keys; + + /// + public ICollection Values => this.columns.Values; + /// public object? this[string key] { @@ -60,12 +79,6 @@ public object? this[string key] set => this.columns[key] = value; } - /// - public ICollection Keys => this.columns.Keys; - - /// - public ICollection Values => this.columns.Values; - /// public void Add(KeyValuePair item) => this.columns.Add(item); @@ -108,24 +121,11 @@ public object? this[string key] /// protected virtual DynamicMetaObject GetMetaObject(Expression parameter) => new DataRowMetaObject(parameter, this); - /// - DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) => this.GetMetaObject(parameter); - /// IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); - /// - /// Reads the value of a column, used as the target of a bound dynamic member read. - /// - private static readonly Func readColumn = static (row, columnName) => row[columnName]; - - /// - /// Writes the value of a column and returns it, used as the target of a bound dynamic member write. - /// - private static readonly Func writeColumn = static (row, columnName, value) => - row[columnName] = value; - - private readonly IDictionary columns = columns; + /// + DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) => this.GetMetaObject(parameter); /// /// Binds member access on a to the columns of the row, so that row.Id resolves to diff --git a/src/DbConnectionPlus/Entities/EntityHelper.cs b/src/DbConnectionPlus/Entities/EntityHelper.cs index 1cd4a9e..9af213e 100644 --- a/src/DbConnectionPlus/Entities/EntityHelper.cs +++ b/src/DbConnectionPlus/Entities/EntityHelper.cs @@ -52,6 +52,8 @@ public static class EntityHelper internal const DynamicallyAccessedMemberTypes TemporaryTableValueMemberTypes = EntityMemberTypes | DynamicallyAccessedMemberTypes.PublicFields; + private static readonly ConcurrentDictionary entityTypeMetadataPerEntityType = []; + /// /// Tries to find a constructor of the type that has parameters compatible to the /// specified expected parameters. @@ -179,52 +181,6 @@ public static EntityTypeMetadata GetEntityTypeMetadata( /// internal static void ResetEntityTypeMetadataCache() => entityTypeMetadataPerEntityType.Clear(); - /// - /// Creates the getter function for the property . - /// - /// The property for which to create the getter function. - /// A function taking an entity and returning the value of . - /// - /// The underlying is resolved on the first call and then kept in the closure, so - /// building the metadata of an entity type costs nothing per property until an accessor is actually used. The - /// unsynchronized assignment is deliberate: two threads racing here produce two equivalent invokers, and either - /// one is correct. - /// - private static Func CreatePropertyGetter(PropertyInfo property) - { - MethodInvoker? getMethodInvoker = null; - - return entity => - { - getMethodInvoker ??= MethodInvoker.Create(property.GetMethod!); - - return getMethodInvoker.Invoke(entity); - }; - } - - /// - /// Creates the setter function for the property . - /// - /// The property for which to create the setter function. - /// An action taking an entity and the value to assign to . - /// - /// The underlying is resolved on the first call and then kept in the closure, so - /// building the metadata of an entity type costs nothing per property until an accessor is actually used. The - /// unsynchronized assignment is deliberate: two threads racing here produce two equivalent invokers, and either - /// one is correct. - /// - private static Action CreatePropertySetter(PropertyInfo property) - { - MethodInvoker? setMethodInvoker = null; - - return (entity, value) => - { - setMethodInvoker ??= MethodInvoker.Create(property.SetMethod!); - - setMethodInvoker.Invoke(entity, value); - }; - } - /// /// Creates the metadata for the entity type . /// @@ -386,5 +342,49 @@ .. propertiesMetadata.Where(p => ); } - private static readonly ConcurrentDictionary entityTypeMetadataPerEntityType = []; + /// + /// Creates the getter function for the property . + /// + /// The property for which to create the getter function. + /// A function taking an entity and returning the value of . + /// + /// The underlying is resolved on the first call and then kept in the closure, so + /// building the metadata of an entity type costs nothing per property until an accessor is actually used. The + /// unsynchronized assignment is deliberate: two threads racing here produce two equivalent invokers, and either + /// one is correct. + /// + private static Func CreatePropertyGetter(PropertyInfo property) + { + MethodInvoker? getMethodInvoker = null; + + return entity => + { + getMethodInvoker ??= MethodInvoker.Create(property.GetMethod!); + + return getMethodInvoker.Invoke(entity); + }; + } + + /// + /// Creates the setter function for the property . + /// + /// The property for which to create the setter function. + /// An action taking an entity and the value to assign to . + /// + /// The underlying is resolved on the first call and then kept in the closure, so + /// building the metadata of an entity type costs nothing per property until an accessor is actually used. The + /// unsynchronized assignment is deliberate: two threads racing here produce two equivalent invokers, and either + /// one is correct. + /// + private static Action CreatePropertySetter(PropertyInfo property) + { + MethodInvoker? setMethodInvoker = null; + + return (entity, value) => + { + setMethodInvoker ??= MethodInvoker.Create(property.SetMethod!); + + setMethodInvoker.Invoke(entity, value); + }; + } } diff --git a/src/DbConnectionPlus/Extensions/Int32Extensions.cs b/src/DbConnectionPlus/Extensions/Int32Extensions.cs index 2516a9a..4a3daf2 100644 --- a/src/DbConnectionPlus/Extensions/Int32Extensions.cs +++ b/src/DbConnectionPlus/Extensions/Int32Extensions.cs @@ -10,6 +10,8 @@ namespace RentADeveloper.DbConnectionPlus.Extensions; /// internal static class Int32Extensions { + private static readonly CultureInfo englishCulture = new("en-US"); + /// /// Turns this number into an ordinal number in english notation, used to denote the position in an ordered sequence /// (e.g. 1st, 2nd, 3rd, 4th). @@ -17,6 +19,4 @@ internal static class Int32Extensions /// The number to ordinalize. /// The ordinalized number in english notation. internal static string OrdinalizeEnglish(this int value) => value.Ordinalize(englishCulture); - - private static readonly CultureInfo englishCulture = new("en-US"); } diff --git a/src/DbConnectionPlus/Extensions/ObjectExtensions.cs b/src/DbConnectionPlus/Extensions/ObjectExtensions.cs index 609a5c8..0d3c6c4 100644 --- a/src/DbConnectionPlus/Extensions/ObjectExtensions.cs +++ b/src/DbConnectionPlus/Extensions/ObjectExtensions.cs @@ -8,6 +8,11 @@ namespace RentADeveloper.DbConnectionPlus.Extensions; /// internal static class ObjectExtensions { + /// + /// The deepest sequence nesting that is rendered before the representation is truncated. + /// + private const int MaxSequenceDepth = 10; + /// /// Gets the string representation of this value suffixed by the fullname of this value's type. /// @@ -29,6 +34,17 @@ internal static string ToDebugString(this object? value) => _ => $"'{FormatValue(value, 0)}' ({value.GetType()})", }; + /// + /// Gets the string representation of a sequence, as its elements separated by commas in square brackets. + /// + /// The sequence of which to get the string representation. + /// The nesting depth at which itself sits. + /// A string representation of . + private static string FormatSequence(IEnumerable values, int depth) => + depth >= MaxSequenceDepth + ? "[...]" + : "[" + string.Join(",", values.Cast().Select(item => FormatValue(item, depth + 1))) + "]"; + /// /// Gets the string representation of a value, without the type suffix. /// @@ -95,20 +111,4 @@ private static string FormatValue(object? value, int depth) => // its message. A type that renders as its own name here simply has no ToString override. _ => value.ToString() ?? string.Empty, }; - - /// - /// Gets the string representation of a sequence, as its elements separated by commas in square brackets. - /// - /// The sequence of which to get the string representation. - /// The nesting depth at which itself sits. - /// A string representation of . - private static string FormatSequence(IEnumerable values, int depth) => - depth >= MaxSequenceDepth - ? "[...]" - : "[" + string.Join(",", values.Cast().Select(item => FormatValue(item, depth + 1))) + "]"; - - /// - /// The deepest sequence nesting that is rendered before the representation is truncated. - /// - private const int MaxSequenceDepth = 10; } diff --git a/src/DbConnectionPlus/Extensions/TypeExtensions.cs b/src/DbConnectionPlus/Extensions/TypeExtensions.cs index 3ce2af8..098391f 100644 --- a/src/DbConnectionPlus/Extensions/TypeExtensions.cs +++ b/src/DbConnectionPlus/Extensions/TypeExtensions.cs @@ -8,6 +8,44 @@ namespace RentADeveloper.DbConnectionPlus.Extensions; /// internal static class TypeExtensions { + private static readonly HashSet builtInTypes = + [ + typeof(bool), + typeof(byte), + typeof(sbyte), + typeof(char), + typeof(decimal), + typeof(double), + typeof(float), + typeof(short), + typeof(ushort), + typeof(int), + typeof(uint), + typeof(long), + typeof(ulong), + typeof(IntPtr), + typeof(UIntPtr), + typeof(string), + typeof(DateTime), + typeof(DateOnly), + typeof(DateTimeOffset), + typeof(TimeSpan), + typeof(TimeOnly), + typeof(Guid), + ]; + + private static readonly HashSet valueTupleTypes = + [ + typeof(ValueTuple<>), + typeof(ValueTuple<,>), + typeof(ValueTuple<,,>), + typeof(ValueTuple<,,,>), + typeof(ValueTuple<,,,,>), + typeof(ValueTuple<,,,,,>), + typeof(ValueTuple<,,,,,,>), + typeof(ValueTuple<,,,,,,,>), + ]; + /// /// Determines whether this type is a built-in .NET type /// (e.g. , , , ...). @@ -92,42 +130,4 @@ internal static bool IsValueTupleType(this Type type) return type.IsGenericType && valueTupleTypes.Contains(type.GetGenericTypeDefinition()); } - - private static readonly HashSet builtInTypes = - [ - typeof(bool), - typeof(byte), - typeof(sbyte), - typeof(char), - typeof(decimal), - typeof(double), - typeof(float), - typeof(short), - typeof(ushort), - typeof(int), - typeof(uint), - typeof(long), - typeof(ulong), - typeof(IntPtr), - typeof(UIntPtr), - typeof(string), - typeof(DateTime), - typeof(DateOnly), - typeof(DateTimeOffset), - typeof(TimeSpan), - typeof(TimeOnly), - typeof(Guid), - ]; - - private static readonly HashSet valueTupleTypes = - [ - typeof(ValueTuple<>), - typeof(ValueTuple<,>), - typeof(ValueTuple<,,>), - typeof(ValueTuple<,,,>), - typeof(ValueTuple<,,,,>), - typeof(ValueTuple<,,,,,>), - typeof(ValueTuple<,,,,,,>), - typeof(ValueTuple<,,,,,,,>), - ]; } diff --git a/src/DbConnectionPlus/Materializers/EntityMaterializerFactory.cs b/src/DbConnectionPlus/Materializers/EntityMaterializerFactory.cs index f2feb72..b664e42 100644 --- a/src/DbConnectionPlus/Materializers/EntityMaterializerFactory.cs +++ b/src/DbConnectionPlus/Materializers/EntityMaterializerFactory.cs @@ -29,6 +29,86 @@ internal static class EntityMaterializerFactory + "application is published with Native AOT. Reach this only from a RuntimeFeature.IsDynamicCodeSupported " + "branch."; + private static readonly ConcurrentDictionary materializerCache = []; + + /// + /// Creates a materializer function that materializes the data in a to an instance of + /// the type using reflection instead of a compiled expression tree. + /// + /// The type of entity to materialize. + /// The for which to create the materializer function. + /// + /// The names of the fields in . + /// The order of the names must match the order of the fields in . + /// + /// + /// The field types of the fields in . + /// The order of the types must match the order of the fields in . + /// + /// + /// A function that materializes the data in a to an instance of the type + /// . + /// + /// + /// + /// + /// + /// is . + /// + /// + /// + /// + /// is . + /// + /// + /// + /// + /// is . + /// + /// + /// + /// + /// + /// + /// This is the materializer for applications published with Native AOT, where no run-time code generation is + /// available. It mirrors the two strategies of and picks + /// between them the same way: constructor injection when the type has a constructor that matches the result + /// set, and a parameterless constructor followed by property setters otherwise. + /// + /// + /// Everything that depends only on the shape of the result set - the field ordinals, the target types, whether a + /// field value needs to be converted, and the property setters - is resolved once, exactly as the compiled + /// expression tree bakes it in. Per row the materializer only walks an array, reads the fields and writes them. + /// The materializer cache is keyed by that shape, so the resolution happens once per shape. + /// + /// + /// The exception types and the exception messages are identical to the ones of the compiled expression tree, so + /// that the behaviour a consumer observes does not depend on how the application was published. + /// + /// + internal static Func CreateReflectionMaterializer< + [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity + >(DbDataReader dataReader, string[] dataReaderFieldNames, Type[] dataReaderFieldTypes) + { + ArgumentNullException.ThrowIfNull(dataReader); + ArgumentNullException.ThrowIfNull(dataReaderFieldNames); + ArgumentNullException.ThrowIfNull(dataReaderFieldTypes); + + var compatibleConstructor = EntityHelper.FindCompatibleConstructor( + typeof(TEntity), + [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type))] + ); + + return compatibleConstructor is null + ? CreateReflectionPropertyMaterializer(dataReader, dataReaderFieldNames, dataReaderFieldTypes) + : CreateReflectionConstructorMaterializer( + dataReader, + dataReaderFieldNames, + dataReaderFieldTypes, + compatibleConstructor + ); + } + /// /// Gets a materializer function that materializes the data in a to an instance of the /// type . @@ -128,7 +208,7 @@ internal static Func GetMaterializer< /// /// Creates a materializer function that materializes the data in a to an instance of - /// the type using reflection instead of a compiled expression tree. + /// the type by compiling an expression tree. /// /// The type of entity to materialize. /// The for which to create the materializer function. @@ -144,274 +224,240 @@ internal static Func GetMaterializer< /// A function that materializes the data in a to an instance of the type /// . /// - /// - /// - /// - /// - /// is . - /// - /// - /// - /// - /// is . - /// - /// - /// - /// - /// is . - /// - /// - /// - /// + /// /// - /// - /// This is the materializer for applications published with Native AOT, where no run-time code generation is - /// available. It mirrors the two strategies of and picks - /// between them the same way: constructor injection when the type has a constructor that matches the result - /// set, and a parameterless constructor followed by property setters otherwise. - /// - /// - /// Everything that depends only on the shape of the result set - the field ordinals, the target types, whether a - /// field value needs to be converted, and the property setters - is resolved once, exactly as the compiled - /// expression tree bakes it in. Per row the materializer only walks an array, reads the fields and writes them. - /// The materializer cache is keyed by that shape, so the resolution happens once per shape. - /// - /// - /// The exception types and the exception messages are identical to the ones of the compiled expression tree, so - /// that the behaviour a consumer observes does not depend on how the application was published. - /// + /// This is the fast path for runtimes that can generate code, and the only implementation the library had + /// before it grew a Native AOT counterpart. It is reached exclusively through the + /// check in ; + /// is the counterpart that produces the same results + /// without generating code. /// - internal static Func CreateReflectionMaterializer< + [RequiresDynamicCode(MaterializerRequiresDynamicCodeMessage)] + private static Delegate CreateExpressionMaterializer< [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity >(DbDataReader dataReader, string[] dataReaderFieldNames, Type[] dataReaderFieldTypes) { - ArgumentNullException.ThrowIfNull(dataReader); - ArgumentNullException.ThrowIfNull(dataReaderFieldNames); - ArgumentNullException.ThrowIfNull(dataReaderFieldTypes); + var entityType = typeof(TEntity); + + /* + * This method creates an expression tree to generate a materializer function instead of using reflection for + * the materialization, because using reflection would be significantly slower. + * Using expression trees also allows us to use the typed GetXXX methods of DbDataReader, which avoids boxing + * in many cases. + */ + + var dataReaderParameterExpression = Expression.Parameter(typeof(DbDataReader), "dataReader"); + var dataReaderFieldValueExpressions = new Expression[dataReader.FieldCount]; + + var fieldOrdinalToTargetType = new Dictionary(dataReader.FieldCount); + var fieldOrdinalToConstructorParameterIndex = new Dictionary(dataReader.FieldCount); var compatibleConstructor = EntityHelper.FindCompatibleConstructor( - typeof(TEntity), + entityType, [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type))] ); - return compatibleConstructor is null - ? CreateReflectionPropertyMaterializer(dataReader, dataReaderFieldNames, dataReaderFieldTypes) - : CreateReflectionConstructorMaterializer( - dataReader, - dataReaderFieldNames, - dataReaderFieldTypes, - compatibleConstructor - ); - } + var entityPropertiesByColumnName = EntityHelper + .GetEntityTypeMetadata(entityType) + .MappedProperties.Where(a => a.CanWrite) + .ToDictionary(a => a.ColumnName, StringComparer.OrdinalIgnoreCase); - /// - /// Creates a reflection-based materializer function that materializes the data in a - /// to an instance of the type by passing the fields of the result set to - /// . - /// - /// The type of entity to materialize. - /// The for which to create the materializer function. - /// - /// The names of the fields in . - /// The order of the names must match the order of the fields in . - /// - /// - /// The field types of the fields in . - /// The order of the types must match the order of the fields in . - /// - /// - /// The constructor of the type whose parameters match the fields of the result - /// set, as returned by . - /// - /// - /// A function that materializes the data in a to an instance of the type - /// . - /// - /// - /// This is the strategy that materializes entities using constructor injection. Each field of the result set is - /// matched to the constructor parameter of the same name, exactly as the compiled expression tree matches it, - /// and the resulting bindings are stored in constructor-argument order. Per row the arguments are therefore - /// read left to right, which is also the order in which the expression tree evaluates them - so when more than - /// one field is unusable, both paths report the same one. - /// - private static Func CreateReflectionConstructorMaterializer( - DbDataReader dataReader, - string[] dataReaderFieldNames, - Type[] dataReaderFieldTypes, - ConstructorInfo compatibleConstructor - ) - { - var entityType = typeof(TEntity); + if (compatibleConstructor is not null) + { + var constructorParameters = compatibleConstructor.GetParameters().ToList(); - var constructorParameters = compatibleConstructor.GetParameters(); - var constructorArgumentBindings = new ReflectionColumnBinding[constructorParameters.Length]; + for (var fieldOrdinal = 0; fieldOrdinal < dataReader.FieldCount; fieldOrdinal++) + { + var constructorParameter = constructorParameters.First(p => + !string.IsNullOrWhiteSpace(p.Name) + && p.Name.Equals(dataReaderFieldNames[fieldOrdinal], StringComparison.OrdinalIgnoreCase) + && ValueConverter.CanConvert(dataReaderFieldTypes[fieldOrdinal], p.ParameterType) + ); + + fieldOrdinalToConstructorParameterIndex.Add( + fieldOrdinal, + constructorParameters.IndexOf(constructorParameter) + ); + + fieldOrdinalToTargetType.Add(fieldOrdinal, constructorParameter.ParameterType); + } + } + else + { + for (var fieldOrdinal = 0; fieldOrdinal < dataReader.FieldCount; fieldOrdinal++) + { + var dataReaderFieldName = dataReaderFieldNames[fieldOrdinal]; + + if (entityPropertiesByColumnName.TryGetValue(dataReaderFieldName, out var entityProperty)) + { + fieldOrdinalToTargetType.Add(fieldOrdinal, entityProperty.PropertyType); + } + else + { + fieldOrdinalToTargetType.Add(fieldOrdinal, dataReaderFieldTypes[fieldOrdinal]); + } + } + } for (var fieldOrdinal = 0; fieldOrdinal < dataReader.FieldCount; fieldOrdinal++) { + var fieldOrdinalExpression = Expression.Constant(fieldOrdinal); + var dataReaderFieldName = dataReaderFieldNames[fieldOrdinal]; + + if (compatibleConstructor is null && !entityPropertiesByColumnName.ContainsKey(dataReaderFieldName)) + { + // No need to read the field when we are using properties to materialize and there is no matching + // property for the field. + continue; + } + var dataReaderFieldType = dataReaderFieldTypes[fieldOrdinal]; + var targetType = fieldOrdinalToTargetType[fieldOrdinal]; - var constructorParameter = constructorParameters.First(p => - !string.IsNullOrWhiteSpace(p.Name) - && p.Name.Equals(dataReaderFieldName, StringComparison.OrdinalIgnoreCase) - && ValueConverter.CanConvert(dataReaderFieldType, p.ParameterType) + // Basically: + // dataReader.GetXXX(fieldOrdinal) + var getFieldValueCallExpression = MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueExpression( + dataReaderParameterExpression, + fieldOrdinalExpression, + fieldOrdinal, + dataReaderFieldName, + dataReaderFieldType ); - constructorArgumentBindings[Array.IndexOf(constructorParameters, constructorParameter)] = - new ReflectionColumnBinding( - dataReaderFieldName, - fieldOrdinal, - MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueFunction( - fieldOrdinal, - dataReaderFieldName, - dataReaderFieldType - ), - dataReaderFieldType != constructorParameter.ParameterType, - constructorParameter.ParameterType - ); - } + /* + * Basically: + * + * if (dataReader.IsDBNull(fieldOrdinal)) + * { + * if (targetType.IsReferenceTypeOrNullableType()) + * { + * default(targetType); + * } + * else + * { + * throw new InvalidCastException(...); + * } + * } + * else + * { + * if (dataReaderFieldType != targetType) + * { + * try + * { + * ValueConverter.ConvertValueToType((Object) dataReader.GetXXX(fieldOrdinal)); + * } + * catch (Exception ex) + * { + * throw new InvalidCastException(..., ex); + * } + * } + * else + * { + * dataReader.GetXXX(fieldOrdinal); + * } + * } + */ - var entityConstructor = ConstructorInvoker.Create(compatibleConstructor); + var exceptionParameterExpression = Expression.Parameter(typeof(Exception)); - return rowDataReader => - MaterializeEntityThroughConstructor( - rowDataReader, - entityType, - entityConstructor, - constructorArgumentBindings - ); - } + Expression isDbNullBranchExpression = targetType.IsReferenceTypeOrNullableType() + ? Expression.Default(targetType) + : Expression.Throw( + Expression.New( + typeof(InvalidCastException).GetConstructor([typeof(string)])!, + Expression.Constant( + $"The column '{dataReaderFieldName}' returned by the SQL statement contains a " + + $"NULL value, but the corresponding property of the type {entityType} is " + + "non-nullable." + ) + ), + targetType + ); - /// - /// Creates a reflection-based materializer function that materializes the data in a - /// to an instance of the type by constructing it with its parameterless - /// constructor and then writing each field of the result set to the property it maps to. - /// - /// The type of entity to materialize. - /// The for which to create the materializer function. - /// - /// The names of the fields in . - /// The order of the names must match the order of the fields in . - /// - /// - /// The field types of the fields in . - /// The order of the types must match the order of the fields in . - /// - /// - /// A function that materializes the data in a to an instance of the type - /// . - /// - /// - /// Callers must have established that the type has a parameterless constructor - /// and no constructor compatible with the result set - does both. Fields - /// without a matching property are never read, which the compiled expression tree does as well. - /// - private static Func CreateReflectionPropertyMaterializer< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >(DbDataReader dataReader, string[] dataReaderFieldNames, Type[] dataReaderFieldTypes) - { - var entityType = typeof(TEntity); + var throwInvalidCastExceptionExpression = Expression.Throw( + Expression.New( + typeof(InvalidCastException).GetConstructor([typeof(string), typeof(Exception)])!, + Expression.Constant( + $"The column '{dataReaderFieldName}' returned by the SQL statement " + + $"contains a value that could not be converted to the type {targetType} " + + $"of the corresponding property of the type {entityType}. See inner " + + "exception for details." + ), + exceptionParameterExpression + ), + targetType + ); - var entityPropertiesByColumnName = EntityHelper - .GetEntityTypeMetadata(entityType) - .MappedProperties.Where(a => a.CanWrite) - .ToDictionary(a => a.ColumnName, StringComparer.OrdinalIgnoreCase); + var convertFieldValueExpression = Expression.TryCatch( + Expression.Convert( + Expression.Call( + null, + MaterializerFactoryHelper.MakeValueConverterConvertValueToTypeMethod(targetType), + Expression.Convert(getFieldValueCallExpression, typeof(object)) + ), + targetType + ), + Expression.Catch(exceptionParameterExpression, throwInvalidCastExceptionExpression) + ); - var entityConstructor = ConstructorInvoker.Create(EntityHelper.FindParameterlessConstructor(entityType)!); + var isNotDbNullBranchExpression = + dataReaderFieldType != targetType ? convertFieldValueExpression : getFieldValueCallExpression; - var propertyBindings = new List(dataReader.FieldCount); + dataReaderFieldValueExpressions[fieldOrdinal] = Expression.Condition( + Expression.Call( + dataReaderParameterExpression, + MaterializerFactoryHelper.DbDataReaderIsDBNullMethod, + fieldOrdinalExpression + ), + isDbNullBranchExpression, + isNotDbNullBranchExpression + ); + } - for (var fieldOrdinal = 0; fieldOrdinal < dataReader.FieldCount; fieldOrdinal++) + Expression bodyExpression; + + if (compatibleConstructor is not null) { - var dataReaderFieldName = dataReaderFieldNames[fieldOrdinal]; + var constructorArgumentExpressions = new Expression[dataReader.FieldCount]; - if (!entityPropertiesByColumnName.TryGetValue(dataReaderFieldName, out var entityProperty)) + for (var fieldOrdinal = 0; fieldOrdinal < dataReader.FieldCount; fieldOrdinal++) { - // No need to read the field when there is no matching property for it. The expression tree skips - // these fields as well, and tests assert that the field is never touched. - continue; - } + var constructorArgumentIndex = fieldOrdinalToConstructorParameterIndex[fieldOrdinal]; - var dataReaderFieldType = dataReaderFieldTypes[fieldOrdinal]; - var targetType = entityProperty.PropertyType; + constructorArgumentExpressions[constructorArgumentIndex] = dataReaderFieldValueExpressions[ + fieldOrdinal + ]; + } - propertyBindings.Add( - new ReflectionPropertyBinding( - new ReflectionColumnBinding( - dataReaderFieldName, - fieldOrdinal, - MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueFunction( - fieldOrdinal, - dataReaderFieldName, - dataReaderFieldType - ), - dataReaderFieldType != targetType, - targetType - ), - // entityPropertiesByColumnName only contains writable properties, so the setter always exists. - entityProperty.PropertySetter! - ) - ); + // Basically: + // new TEntity(constructorArgumentExpressions...) + bodyExpression = Expression.New(compatibleConstructor, constructorArgumentExpressions); } + else + { + var memberBindings = new List(); - var resolvedPropertyBindings = propertyBindings.ToArray(); + for (var fieldOrdinal = 0; fieldOrdinal < dataReader.FieldCount; fieldOrdinal++) + { + var dataReaderFieldName = dataReaderFieldNames[fieldOrdinal]; - return rowDataReader => - MaterializeEntityThroughProperties( - rowDataReader, - entityType, - entityConstructor, - resolvedPropertyBindings - ); - } + if (!entityPropertiesByColumnName.TryGetValue(dataReaderFieldName, out var entityProperty)) + { + continue; + } - /// - /// Throws if none of the fields of the result set can be mapped to a writable property of - /// . - /// - /// The entity type the result set is being materialized to. - /// The field names of the result set. - /// The writable properties of the entity type, by column name. - /// - /// The result set has fields, but none of them maps to a writable property of . - /// - /// - /// - /// Without this check, materialization silently succeeds and returns entities whose properties are all left at - /// their default values, which is indistinguishable from a query that legitimately returned default data. - /// - /// - /// The check matters most in an application that is trimmed or published with Native AOT. If a - /// annotation is missing anywhere on the call path, the - /// trimmer removes the entity's properties, reflection then reports fewer members than the type really has, and - /// every column silently fails to bind. Failing loudly here is the backstop for that. - /// - /// - private static void GuardAgainstResultSetBindingNoProperties( - Type entityType, - string[] dataReaderFieldNames, - Dictionary entityPropertiesByColumnName - ) - { - if (dataReaderFieldNames.Length == 0) - { - return; - } + memberBindings.Add( + Expression.Bind(entityProperty.PropertyInfo, dataReaderFieldValueExpressions[fieldOrdinal]) + ); + } - if (dataReaderFieldNames.Any(entityPropertiesByColumnName.ContainsKey)) - { - return; + // Basically: + // new TEntity { Property1 = ..., Property2 = ..., ... } + bodyExpression = Expression.MemberInit(Expression.New(entityType), memberBindings); } - throw new InvalidOperationException( - $"None of the {dataReaderFieldNames.Length} field(s) of the result set " - + $"({string.Join(", ", dataReaderFieldNames)}) could be mapped to a writable property of the entity " - + $"type {entityType}. Materializing the result set would return entities whose properties are all left " - + "at their default values. Check that the field names of the result set match the property names, or " - + "the mapped column names, of the entity type. If the application is trimmed or published with Native " - + "AOT, this usually means the properties of the entity type were removed by the trimmer because a " - + "[DynamicallyAccessedMembers] annotation is missing on the call path." - ); + return Expression.Lambda(bodyExpression, dataReaderParameterExpression).Compile(); } /// @@ -521,8 +567,9 @@ [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) } /// - /// Creates a materializer function that materializes the data in a to an instance of - /// the type by compiling an expression tree. + /// Creates a reflection-based materializer function that materializes the data in a + /// to an instance of the type by passing the fields of the result set to + /// . /// /// The type of entity to materialize. /// The for which to create the materializer function. @@ -534,244 +581,199 @@ [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) /// The field types of the fields in . /// The order of the types must match the order of the fields in . /// + /// + /// The constructor of the type whose parameters match the fields of the result + /// set, as returned by . + /// /// /// A function that materializes the data in a to an instance of the type /// . /// - /// /// - /// This is the fast path for runtimes that can generate code, and the only implementation the library had - /// before it grew a Native AOT counterpart. It is reached exclusively through the - /// check in ; - /// is the counterpart that produces the same results - /// without generating code. + /// This is the strategy that materializes entities using constructor injection. Each field of the result set is + /// matched to the constructor parameter of the same name, exactly as the compiled expression tree matches it, + /// and the resulting bindings are stored in constructor-argument order. Per row the arguments are therefore + /// read left to right, which is also the order in which the expression tree evaluates them - so when more than + /// one field is unusable, both paths report the same one. /// - [RequiresDynamicCode(MaterializerRequiresDynamicCodeMessage)] - private static Delegate CreateExpressionMaterializer< - [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity - >(DbDataReader dataReader, string[] dataReaderFieldNames, Type[] dataReaderFieldTypes) + private static Func CreateReflectionConstructorMaterializer( + DbDataReader dataReader, + string[] dataReaderFieldNames, + Type[] dataReaderFieldTypes, + ConstructorInfo compatibleConstructor + ) { var entityType = typeof(TEntity); - /* - * This method creates an expression tree to generate a materializer function instead of using reflection for - * the materialization, because using reflection would be significantly slower. - * Using expression trees also allows us to use the typed GetXXX methods of DbDataReader, which avoids boxing - * in many cases. - */ + var constructorParameters = compatibleConstructor.GetParameters(); + var constructorArgumentBindings = new ReflectionColumnBinding[constructorParameters.Length]; - var dataReaderParameterExpression = Expression.Parameter(typeof(DbDataReader), "dataReader"); - var dataReaderFieldValueExpressions = new Expression[dataReader.FieldCount]; + for (var fieldOrdinal = 0; fieldOrdinal < dataReader.FieldCount; fieldOrdinal++) + { + var dataReaderFieldName = dataReaderFieldNames[fieldOrdinal]; + var dataReaderFieldType = dataReaderFieldTypes[fieldOrdinal]; - var fieldOrdinalToTargetType = new Dictionary(dataReader.FieldCount); - var fieldOrdinalToConstructorParameterIndex = new Dictionary(dataReader.FieldCount); + var constructorParameter = constructorParameters.First(p => + !string.IsNullOrWhiteSpace(p.Name) + && p.Name.Equals(dataReaderFieldName, StringComparison.OrdinalIgnoreCase) + && ValueConverter.CanConvert(dataReaderFieldType, p.ParameterType) + ); - var compatibleConstructor = EntityHelper.FindCompatibleConstructor( - entityType, - [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type))] - ); + constructorArgumentBindings[Array.IndexOf(constructorParameters, constructorParameter)] = + new ReflectionColumnBinding( + dataReaderFieldName, + fieldOrdinal, + MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueFunction( + fieldOrdinal, + dataReaderFieldName, + dataReaderFieldType + ), + dataReaderFieldType != constructorParameter.ParameterType, + constructorParameter.ParameterType + ); + } - var entityPropertiesByColumnName = EntityHelper - .GetEntityTypeMetadata(entityType) - .MappedProperties.Where(a => a.CanWrite) - .ToDictionary(a => a.ColumnName, StringComparer.OrdinalIgnoreCase); + var entityConstructor = ConstructorInvoker.Create(compatibleConstructor); - if (compatibleConstructor is not null) - { - var constructorParameters = compatibleConstructor.GetParameters().ToList(); + return rowDataReader => + MaterializeEntityThroughConstructor( + rowDataReader, + entityType, + entityConstructor, + constructorArgumentBindings + ); + } - for (var fieldOrdinal = 0; fieldOrdinal < dataReader.FieldCount; fieldOrdinal++) - { - var constructorParameter = constructorParameters.First(p => - !string.IsNullOrWhiteSpace(p.Name) - && p.Name.Equals(dataReaderFieldNames[fieldOrdinal], StringComparison.OrdinalIgnoreCase) - && ValueConverter.CanConvert(dataReaderFieldTypes[fieldOrdinal], p.ParameterType) - ); + /// + /// Creates a reflection-based materializer function that materializes the data in a + /// to an instance of the type by constructing it with its parameterless + /// constructor and then writing each field of the result set to the property it maps to. + /// + /// The type of entity to materialize. + /// The for which to create the materializer function. + /// + /// The names of the fields in . + /// The order of the names must match the order of the fields in . + /// + /// + /// The field types of the fields in . + /// The order of the types must match the order of the fields in . + /// + /// + /// A function that materializes the data in a to an instance of the type + /// . + /// + /// + /// Callers must have established that the type has a parameterless constructor + /// and no constructor compatible with the result set - does both. Fields + /// without a matching property are never read, which the compiled expression tree does as well. + /// + private static Func CreateReflectionPropertyMaterializer< + [DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity + >(DbDataReader dataReader, string[] dataReaderFieldNames, Type[] dataReaderFieldTypes) + { + var entityType = typeof(TEntity); - fieldOrdinalToConstructorParameterIndex.Add( - fieldOrdinal, - constructorParameters.IndexOf(constructorParameter) - ); + var entityPropertiesByColumnName = EntityHelper + .GetEntityTypeMetadata(entityType) + .MappedProperties.Where(a => a.CanWrite) + .ToDictionary(a => a.ColumnName, StringComparer.OrdinalIgnoreCase); - fieldOrdinalToTargetType.Add(fieldOrdinal, constructorParameter.ParameterType); - } - } - else - { - for (var fieldOrdinal = 0; fieldOrdinal < dataReader.FieldCount; fieldOrdinal++) - { - var dataReaderFieldName = dataReaderFieldNames[fieldOrdinal]; + var entityConstructor = ConstructorInvoker.Create(EntityHelper.FindParameterlessConstructor(entityType)!); - if (entityPropertiesByColumnName.TryGetValue(dataReaderFieldName, out var entityProperty)) - { - fieldOrdinalToTargetType.Add(fieldOrdinal, entityProperty.PropertyType); - } - else - { - fieldOrdinalToTargetType.Add(fieldOrdinal, dataReaderFieldTypes[fieldOrdinal]); - } - } - } + var propertyBindings = new List(dataReader.FieldCount); for (var fieldOrdinal = 0; fieldOrdinal < dataReader.FieldCount; fieldOrdinal++) { - var fieldOrdinalExpression = Expression.Constant(fieldOrdinal); - var dataReaderFieldName = dataReaderFieldNames[fieldOrdinal]; - if (compatibleConstructor is null && !entityPropertiesByColumnName.ContainsKey(dataReaderFieldName)) + if (!entityPropertiesByColumnName.TryGetValue(dataReaderFieldName, out var entityProperty)) { - // No need to read the field when we are using properties to materialize and there is no matching - // property for the field. + // No need to read the field when there is no matching property for it. The expression tree skips + // these fields as well, and tests assert that the field is never touched. continue; } var dataReaderFieldType = dataReaderFieldTypes[fieldOrdinal]; - var targetType = fieldOrdinalToTargetType[fieldOrdinal]; - - // Basically: - // dataReader.GetXXX(fieldOrdinal) - var getFieldValueCallExpression = MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueExpression( - dataReaderParameterExpression, - fieldOrdinalExpression, - fieldOrdinal, - dataReaderFieldName, - dataReaderFieldType - ); - - /* - * Basically: - * - * if (dataReader.IsDBNull(fieldOrdinal)) - * { - * if (targetType.IsReferenceTypeOrNullableType()) - * { - * default(targetType); - * } - * else - * { - * throw new InvalidCastException(...); - * } - * } - * else - * { - * if (dataReaderFieldType != targetType) - * { - * try - * { - * ValueConverter.ConvertValueToType((Object) dataReader.GetXXX(fieldOrdinal)); - * } - * catch (Exception ex) - * { - * throw new InvalidCastException(..., ex); - * } - * } - * else - * { - * dataReader.GetXXX(fieldOrdinal); - * } - * } - */ - - var exceptionParameterExpression = Expression.Parameter(typeof(Exception)); - - Expression isDbNullBranchExpression = targetType.IsReferenceTypeOrNullableType() - ? Expression.Default(targetType) - : Expression.Throw( - Expression.New( - typeof(InvalidCastException).GetConstructor([typeof(string)])!, - Expression.Constant( - $"The column '{dataReaderFieldName}' returned by the SQL statement contains a " - + $"NULL value, but the corresponding property of the type {entityType} is " - + "non-nullable." - ) - ), - targetType - ); - - var throwInvalidCastExceptionExpression = Expression.Throw( - Expression.New( - typeof(InvalidCastException).GetConstructor([typeof(string), typeof(Exception)])!, - Expression.Constant( - $"The column '{dataReaderFieldName}' returned by the SQL statement " - + $"contains a value that could not be converted to the type {targetType} " - + $"of the corresponding property of the type {entityType}. See inner " - + "exception for details." - ), - exceptionParameterExpression - ), - targetType - ); + var targetType = entityProperty.PropertyType; - var convertFieldValueExpression = Expression.TryCatch( - Expression.Convert( - Expression.Call( - null, - MaterializerFactoryHelper.MakeValueConverterConvertValueToTypeMethod(targetType), - Expression.Convert(getFieldValueCallExpression, typeof(object)) + propertyBindings.Add( + new ReflectionPropertyBinding( + new ReflectionColumnBinding( + dataReaderFieldName, + fieldOrdinal, + MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueFunction( + fieldOrdinal, + dataReaderFieldName, + dataReaderFieldType + ), + dataReaderFieldType != targetType, + targetType ), - targetType - ), - Expression.Catch(exceptionParameterExpression, throwInvalidCastExceptionExpression) + // entityPropertiesByColumnName only contains writable properties, so the setter always exists. + entityProperty.PropertySetter! + ) ); + } - var isNotDbNullBranchExpression = - dataReaderFieldType != targetType ? convertFieldValueExpression : getFieldValueCallExpression; + var resolvedPropertyBindings = propertyBindings.ToArray(); - dataReaderFieldValueExpressions[fieldOrdinal] = Expression.Condition( - Expression.Call( - dataReaderParameterExpression, - MaterializerFactoryHelper.DbDataReaderIsDBNullMethod, - fieldOrdinalExpression - ), - isDbNullBranchExpression, - isNotDbNullBranchExpression + return rowDataReader => + MaterializeEntityThroughProperties( + rowDataReader, + entityType, + entityConstructor, + resolvedPropertyBindings ); - } - - Expression bodyExpression; + } - if (compatibleConstructor is not null) + /// + /// Throws if none of the fields of the result set can be mapped to a writable property of + /// . + /// + /// The entity type the result set is being materialized to. + /// The field names of the result set. + /// The writable properties of the entity type, by column name. + /// + /// The result set has fields, but none of them maps to a writable property of . + /// + /// + /// + /// Without this check, materialization silently succeeds and returns entities whose properties are all left at + /// their default values, which is indistinguishable from a query that legitimately returned default data. + /// + /// + /// The check matters most in an application that is trimmed or published with Native AOT. If a + /// annotation is missing anywhere on the call path, the + /// trimmer removes the entity's properties, reflection then reports fewer members than the type really has, and + /// every column silently fails to bind. Failing loudly here is the backstop for that. + /// + /// + private static void GuardAgainstResultSetBindingNoProperties( + Type entityType, + string[] dataReaderFieldNames, + Dictionary entityPropertiesByColumnName + ) + { + if (dataReaderFieldNames.Length == 0) { - var constructorArgumentExpressions = new Expression[dataReader.FieldCount]; - - for (var fieldOrdinal = 0; fieldOrdinal < dataReader.FieldCount; fieldOrdinal++) - { - var constructorArgumentIndex = fieldOrdinalToConstructorParameterIndex[fieldOrdinal]; - - constructorArgumentExpressions[constructorArgumentIndex] = dataReaderFieldValueExpressions[ - fieldOrdinal - ]; - } - - // Basically: - // new TEntity(constructorArgumentExpressions...) - bodyExpression = Expression.New(compatibleConstructor, constructorArgumentExpressions); + return; } - else - { - var memberBindings = new List(); - - for (var fieldOrdinal = 0; fieldOrdinal < dataReader.FieldCount; fieldOrdinal++) - { - var dataReaderFieldName = dataReaderFieldNames[fieldOrdinal]; - - if (!entityPropertiesByColumnName.TryGetValue(dataReaderFieldName, out var entityProperty)) - { - continue; - } - - memberBindings.Add( - Expression.Bind(entityProperty.PropertyInfo, dataReaderFieldValueExpressions[fieldOrdinal]) - ); - } - // Basically: - // new TEntity { Property1 = ..., Property2 = ..., ... } - bodyExpression = Expression.MemberInit(Expression.New(entityType), memberBindings); + if (dataReaderFieldNames.Any(entityPropertiesByColumnName.ContainsKey)) + { + return; } - return Expression.Lambda(bodyExpression, dataReaderParameterExpression).Compile(); + throw new InvalidOperationException( + $"None of the {dataReaderFieldNames.Length} field(s) of the result set " + + $"({string.Join(", ", dataReaderFieldNames)}) could be mapped to a writable property of the entity " + + $"type {entityType}. Materializing the result set would return entities whose properties are all left " + + "at their default values. Check that the field names of the result set match the property names, or " + + "the mapped column names, of the entity type. If the application is trimmed or published with Native " + + "AOT, this usually means the properties of the entity type were removed by the trimmer because a " + + "[DynamicallyAccessedMembers] annotation is missing on the call path." + ); } /// @@ -1043,8 +1045,6 @@ [.. dataReaderFieldNames.Zip(dataReaderFieldTypes, (name, type) => (name, type)) } } - private static readonly ConcurrentDictionary materializerCache = []; - /// /// A cache key used to uniquely identify an entity materializer. /// @@ -1068,15 +1068,18 @@ Type[] dataReaderFieldTypes /// public Type EntityType { get; } = entityType; + private string[] DataReaderFieldNames { get; } = dataReaderFieldNames; + private Type[] DataReaderFieldTypes { get; } = dataReaderFieldTypes; + + /// + public override bool Equals(object? obj) => obj is MaterializerCacheKey other && this.Equals(other); + /// public bool Equals(MaterializerCacheKey other) => this.EntityType == other.EntityType && this.DataReaderFieldNames.SequenceEqual(other.DataReaderFieldNames) && this.DataReaderFieldTypes.SequenceEqual(other.DataReaderFieldTypes); - /// - public override bool Equals(object? obj) => obj is MaterializerCacheKey other && this.Equals(other); - /// public override int GetHashCode() { @@ -1096,9 +1099,6 @@ public override int GetHashCode() return hashCode.ToHashCode(); } - - private string[] DataReaderFieldNames { get; } = dataReaderFieldNames; - private Type[] DataReaderFieldTypes { get; } = dataReaderFieldTypes; } /// diff --git a/src/DbConnectionPlus/Materializers/MaterializerFactoryHelper.cs b/src/DbConnectionPlus/Materializers/MaterializerFactoryHelper.cs index d629565..8514087 100644 --- a/src/DbConnectionPlus/Materializers/MaterializerFactoryHelper.cs +++ b/src/DbConnectionPlus/Materializers/MaterializerFactoryHelper.cs @@ -13,6 +13,67 @@ namespace RentADeveloper.DbConnectionPlus.Materializers; /// internal static class MaterializerFactoryHelper { + private static readonly Dictionary dbDataReaderTypedGetMethods = new() + { + { typeof(bool), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetBoolean))! }, + { typeof(byte), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetByte))! }, + { typeof(DateTime), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetDateTime))! }, + { typeof(decimal), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetDecimal))! }, + { typeof(double), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetDouble))! }, + { typeof(float), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetFloat))! }, + { typeof(Guid), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetGuid))! }, + { typeof(short), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetInt16))! }, + { typeof(int), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetInt32))! }, + { typeof(long), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetInt64))! }, + { typeof(string), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetString))! }, + }; + + /// + /// The functions that read a field value using the same typed .GetXXX method as + /// , for the materializer path that cannot compile an expression tree. + /// + /// + /// The key set must stay identical to the key set of , otherwise the + /// two materializer paths disagree on which field types are supported. + /// + private static readonly Dictionary> dbDataReaderTypedGetValueFunctions = + new() + { + { typeof(bool), static (dataReader, fieldOrdinal) => dataReader.GetBoolean(fieldOrdinal) }, + { typeof(byte), static (dataReader, fieldOrdinal) => dataReader.GetByte(fieldOrdinal) }, + { typeof(DateTime), static (dataReader, fieldOrdinal) => dataReader.GetDateTime(fieldOrdinal) }, + { typeof(decimal), static (dataReader, fieldOrdinal) => dataReader.GetDecimal(fieldOrdinal) }, + { typeof(double), static (dataReader, fieldOrdinal) => dataReader.GetDouble(fieldOrdinal) }, + { typeof(float), static (dataReader, fieldOrdinal) => dataReader.GetFloat(fieldOrdinal) }, + { typeof(Guid), static (dataReader, fieldOrdinal) => dataReader.GetGuid(fieldOrdinal) }, + { typeof(short), static (dataReader, fieldOrdinal) => dataReader.GetInt16(fieldOrdinal) }, + { typeof(int), static (dataReader, fieldOrdinal) => dataReader.GetInt32(fieldOrdinal) }, + { typeof(long), static (dataReader, fieldOrdinal) => dataReader.GetInt64(fieldOrdinal) }, + { typeof(string), static (dataReader, fieldOrdinal) => dataReader.GetString(fieldOrdinal) }, + }; + + /// + /// The field types has no typed GetXXX method for, and which + /// therefore reads through + /// instead. + /// + private static readonly HashSet dbDataReaderUntypedFieldTypes = + [ + typeof(byte[]), + typeof(DateOnly), + typeof(DateTimeOffset), + typeof(TimeOnly), + typeof(TimeSpan), + ]; + + /// + /// The generic method definition of the method, cached + /// for . + /// + private static readonly MethodInfo valueConverterConvertValueToTypeMethod = typeof(ValueConverter) + .GetMethods(BindingFlags.Static | BindingFlags.NonPublic) + .First(m => m is { Name: nameof(ValueConverter.ConvertValueToType), IsGenericMethod: true }); + /// /// The method. /// @@ -44,50 +105,6 @@ internal static class MaterializerFactoryHelper internal static PropertyInfo StringLengthProperty { get; } = typeof(string).GetProperty(nameof(String.Length), BindingFlags.Instance | BindingFlags.Public)!; - /// - /// Specializes over , so that - /// a compiled expression tree can call the generic - /// directly. - /// - /// The type to specialize the method over. - /// - /// The method, specialized over - /// . - /// - /// - /// - /// This exists as its own method purely so that the IL2060 suppression below covers one line of code - /// instead of the whole expression-building method it is called from. Both materializer factories call it. - /// - /// - /// The suppression is sound rather than convenient, and provably so: - /// declares no - /// on its type parameter. IL2060 reports that the - /// requirements of a runtime-specialized generic method cannot be guaranteed; here there are no requirements to - /// guarantee, so there is nothing the trimmer could remove and nothing for a consumer to act on. Whether the - /// conversion reflects over the target type at all is a question about the converters, which are annotation-free - /// and verified so: the trim analyzers report nothing for ValueConverter or EnumConverter. - /// - /// - /// is a different matter and is kept: specializing a generic method - /// over a value type at run time genuinely needs code generation. Only the callers that are guarded by - /// may reach this. - /// - /// - [RequiresDynamicCode( - "Specializing a generic method over a value type at run time is not supported when the application is " - + "published with Native AOT. Call this only from a RuntimeFeature.IsDynamicCodeSupported branch." - )] - [UnconditionalSuppressMessage( - "Trimming", - "IL2060:MakeGenericMethod call cannot be statically analyzed", - Justification = "ValueConverter.ConvertValueToType declares no DynamicallyAccessedMembers on TTarget, so the " - + "specialized instantiation has no requirements that trimming could fail to preserve. Reaching this " - + "method at all requires a RuntimeFeature.IsDynamicCodeSupported branch." - )] - internal static MethodInfo MakeValueConverterConvertValueToTypeMethod(Type targetType) => - valueConverterConvertValueToTypeMethod.MakeGenericMethod(targetType); - /// /// Creates an that gets the value of a field of the specified field type from a /// using one of the typed .GetXXX methods. @@ -285,64 +302,47 @@ internal static bool IsDbDataReaderTypedGetMethodAvailable(Type fieldType) return dbDataReaderTypedGetMethods.ContainsKey(fieldType) || dbDataReaderUntypedFieldTypes.Contains(fieldType); } - private static readonly Dictionary dbDataReaderTypedGetMethods = new() - { - { typeof(bool), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetBoolean))! }, - { typeof(byte), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetByte))! }, - { typeof(DateTime), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetDateTime))! }, - { typeof(decimal), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetDecimal))! }, - { typeof(double), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetDouble))! }, - { typeof(float), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetFloat))! }, - { typeof(Guid), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetGuid))! }, - { typeof(short), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetInt16))! }, - { typeof(int), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetInt32))! }, - { typeof(long), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetInt64))! }, - { typeof(string), typeof(DbDataReader).GetMethod(nameof(DbDataReader.GetString))! }, - }; - /// - /// The functions that read a field value using the same typed .GetXXX method as - /// , for the materializer path that cannot compile an expression tree. + /// Specializes over , so that + /// a compiled expression tree can call the generic + /// directly. /// + /// The type to specialize the method over. + /// + /// The method, specialized over + /// . + /// /// - /// The key set must stay identical to the key set of , otherwise the - /// two materializer paths disagree on which field types are supported. + /// + /// This exists as its own method purely so that the IL2060 suppression below covers one line of code + /// instead of the whole expression-building method it is called from. Both materializer factories call it. + /// + /// + /// The suppression is sound rather than convenient, and provably so: + /// declares no + /// on its type parameter. IL2060 reports that the + /// requirements of a runtime-specialized generic method cannot be guaranteed; here there are no requirements to + /// guarantee, so there is nothing the trimmer could remove and nothing for a consumer to act on. Whether the + /// conversion reflects over the target type at all is a question about the converters, which are annotation-free + /// and verified so: the trim analyzers report nothing for ValueConverter or EnumConverter. + /// + /// + /// is a different matter and is kept: specializing a generic method + /// over a value type at run time genuinely needs code generation. Only the callers that are guarded by + /// may reach this. + /// /// - private static readonly Dictionary> dbDataReaderTypedGetValueFunctions = - new() - { - { typeof(bool), static (dataReader, fieldOrdinal) => dataReader.GetBoolean(fieldOrdinal) }, - { typeof(byte), static (dataReader, fieldOrdinal) => dataReader.GetByte(fieldOrdinal) }, - { typeof(DateTime), static (dataReader, fieldOrdinal) => dataReader.GetDateTime(fieldOrdinal) }, - { typeof(decimal), static (dataReader, fieldOrdinal) => dataReader.GetDecimal(fieldOrdinal) }, - { typeof(double), static (dataReader, fieldOrdinal) => dataReader.GetDouble(fieldOrdinal) }, - { typeof(float), static (dataReader, fieldOrdinal) => dataReader.GetFloat(fieldOrdinal) }, - { typeof(Guid), static (dataReader, fieldOrdinal) => dataReader.GetGuid(fieldOrdinal) }, - { typeof(short), static (dataReader, fieldOrdinal) => dataReader.GetInt16(fieldOrdinal) }, - { typeof(int), static (dataReader, fieldOrdinal) => dataReader.GetInt32(fieldOrdinal) }, - { typeof(long), static (dataReader, fieldOrdinal) => dataReader.GetInt64(fieldOrdinal) }, - { typeof(string), static (dataReader, fieldOrdinal) => dataReader.GetString(fieldOrdinal) }, - }; - - /// - /// The field types has no typed GetXXX method for, and which - /// therefore reads through - /// instead. - /// - private static readonly HashSet dbDataReaderUntypedFieldTypes = - [ - typeof(byte[]), - typeof(DateOnly), - typeof(DateTimeOffset), - typeof(TimeOnly), - typeof(TimeSpan), - ]; - - /// - /// The generic method definition of the method, cached - /// for . - /// - private static readonly MethodInfo valueConverterConvertValueToTypeMethod = typeof(ValueConverter) - .GetMethods(BindingFlags.Static | BindingFlags.NonPublic) - .First(m => m is { Name: nameof(ValueConverter.ConvertValueToType), IsGenericMethod: true }); + [RequiresDynamicCode( + "Specializing a generic method over a value type at run time is not supported when the application is " + + "published with Native AOT. Call this only from a RuntimeFeature.IsDynamicCodeSupported branch." + )] + [UnconditionalSuppressMessage( + "Trimming", + "IL2060:MakeGenericMethod call cannot be statically analyzed", + Justification = "ValueConverter.ConvertValueToType declares no DynamicallyAccessedMembers on TTarget, so the " + + "specialized instantiation has no requirements that trimming could fail to preserve. Reaching this " + + "method at all requires a RuntimeFeature.IsDynamicCodeSupported branch." + )] + internal static MethodInfo MakeValueConverterConvertValueToTypeMethod(Type targetType) => + valueConverterConvertValueToTypeMethod.MakeGenericMethod(targetType); } diff --git a/src/DbConnectionPlus/Materializers/ValueTupleMaterializerFactory.cs b/src/DbConnectionPlus/Materializers/ValueTupleMaterializerFactory.cs index 7ea77f3..da16181 100644 --- a/src/DbConnectionPlus/Materializers/ValueTupleMaterializerFactory.cs +++ b/src/DbConnectionPlus/Materializers/ValueTupleMaterializerFactory.cs @@ -61,6 +61,108 @@ internal static class ValueTupleMaterializerFactory /// private const int ValueTupleFieldCountBeforeNesting = 7; + private static readonly ConcurrentDictionary materializerCache = []; + + /// + /// Creates a materializer function that materializes the data in a to an instance of + /// the value tuple type using reflection instead of a compiled expression + /// tree. + /// + /// The type of value tuple to materialize. + /// The for which to create the materializer function. + /// + /// The names of the fields in . + /// The order of the names must match the order of the fields in . + /// + /// + /// The field types of the fields in . + /// The order of the types must match the order of the fields in . + /// + /// + /// A function that materializes the data in a to an instance of the value tuple type + /// . + /// + /// + /// + /// + /// + /// is . + /// + /// + /// + /// + /// is . + /// + /// + /// + /// + /// is . + /// + /// + /// + /// + /// + /// + /// This is the materializer for applications published with Native AOT, where no run-time code generation is + /// available. Value tuples are materialized ordinal-positionally, exactly as + /// materializes them, including value tuples with more + /// than seven fields, which the runtime represents as nested value tuples. + /// + /// + /// Everything that depends only on the shape of the result set - the field ordinals, the target types, whether a + /// field value needs to be converted, and the constructors of the value tuple types - is resolved once, exactly + /// as the compiled expression tree bakes it in. Per row the materializer only walks an array, reads the fields + /// and passes them to the constructors. The materializer cache is keyed by that shape, so the resolution happens + /// once per shape. + /// + /// + /// The exception types and the exception messages are identical to the ones of the compiled expression tree, so + /// that the behaviour a consumer observes does not depend on how the application was published. + /// + /// + internal static Func CreateReflectionMaterializer< + [DynamicallyAccessedMembers(ValueTupleMemberTypes)] TValueTuple + >(DbDataReader dataReader, string[] dataReaderFieldNames, Type[] dataReaderFieldTypes) + { + ArgumentNullException.ThrowIfNull(dataReader); + ArgumentNullException.ThrowIfNull(dataReaderFieldNames); + ArgumentNullException.ThrowIfNull(dataReaderFieldTypes); + + var valueTupleType = typeof(TValueTuple); + + // Resolved here rather than taken from the caller, so that this method can be reached directly from a test: + // on the JIT the dispatch in CreateMaterializer always picks the expression tree. + var valueTupleFieldTypes = GetValueTupleFieldTypes(valueTupleType); + + var columnBindings = new ReflectionColumnBinding[dataReader.FieldCount]; + + for (var fieldOrdinal = 0; fieldOrdinal < dataReader.FieldCount; fieldOrdinal++) + { + var dataReaderFieldName = dataReaderFieldNames[fieldOrdinal]; + var dataReaderFieldType = dataReaderFieldTypes[fieldOrdinal]; + var targetType = valueTupleFieldTypes[fieldOrdinal]; + + columnBindings[fieldOrdinal] = new ReflectionColumnBinding( + GetColumnNameOrPosition(fieldOrdinal, dataReaderFieldName), + fieldOrdinal, + MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueFunction( + fieldOrdinal, + dataReaderFieldName, + dataReaderFieldType + ), + dataReaderFieldType != targetType, + targetType + ); + } + + var valueTupleConstructors = GetValueTupleConstructors(valueTupleType) + .Select(ConstructorInvoker.Create) + .ToArray(); + + return rowDataReader => + MaterializeValueTuple(rowDataReader, valueTupleType, valueTupleConstructors, columnBindings); + } + /// /// Gets a materializer function that materializes the data in a to an instance of the /// value tuple type . @@ -171,164 +273,53 @@ internal static Func GetMaterializer< } /// - /// Creates a materializer function that materializes the data in a to an instance of - /// the value tuple type using reflection instead of a compiled expression - /// tree. + /// Constructs the value tuple that holds . /// - /// The type of value tuple to materialize. - /// The for which to create the materializer function. - /// - /// The names of the fields in . - /// The order of the names must match the order of the fields in . + /// + /// The constructors of the value tuple types, from the outermost to the innermost, as returned by + /// . /// - /// - /// The field types of the fields in . - /// The order of the types must match the order of the fields in . + /// + /// The value of every field of the value tuple, including the fields of all nested value tuples, in the order in + /// which the fields are declared. /// - /// - /// A function that materializes the data in a to an instance of the value tuple type - /// . - /// - /// - /// - /// - /// - /// is . - /// - /// - /// - /// - /// is . - /// - /// - /// - /// - /// is . - /// - /// - /// - /// + /// The constructed value tuple, boxed. /// - /// - /// This is the materializer for applications published with Native AOT, where no run-time code generation is - /// available. Value tuples are materialized ordinal-positionally, exactly as - /// materializes them, including value tuples with more - /// than seven fields, which the runtime represents as nested value tuples. - /// - /// - /// Everything that depends only on the shape of the result set - the field ordinals, the target types, whether a - /// field value needs to be converted, and the constructors of the value tuple types - is resolved once, exactly - /// as the compiled expression tree bakes it in. Per row the materializer only walks an array, reads the fields - /// and passes them to the constructors. The materializer cache is keyed by that shape, so the resolution happens - /// once per shape. - /// - /// - /// The exception types and the exception messages are identical to the ones of the compiled expression tree, so - /// that the behaviour a consumer observes does not depend on how the application was published. - /// + /// This does the same as the tail of , which builds the + /// same nesting out of instead of constructing it. /// - internal static Func CreateReflectionMaterializer< - [DynamicallyAccessedMembers(ValueTupleMemberTypes)] TValueTuple - >(DbDataReader dataReader, string[] dataReaderFieldNames, Type[] dataReaderFieldTypes) + private static object ConstructValueTuple(ConstructorInvoker[] valueTupleConstructors, object?[] fieldValues) { - ArgumentNullException.ThrowIfNull(dataReader); - ArgumentNullException.ThrowIfNull(dataReaderFieldNames); - ArgumentNullException.ThrowIfNull(dataReaderFieldTypes); - - var valueTupleType = typeof(TValueTuple); + // In C# value tuples with more than 7 fields are represented as nested value tuples. + // E.g. a ValueTuple with 15 fields is represented as: + // ValueTuple>> + // In this case we need to create the nested value tuples from the inside out. - // Resolved here rather than taken from the caller, so that this method can be reached directly from a test: - // on the JIT the dispatch in CreateMaterializer always picks the expression tree. - var valueTupleFieldTypes = GetValueTupleFieldTypes(valueTupleType); + // So we chunk the field values into groups of 7, which gives us the field values of one of those value + // tuples per chunk. The chunks are in the same order as valueTupleConstructors: the first chunk and the + // first constructor belong to the outermost value tuple, the last ones to the innermost value tuple. + var fieldValueChunks = fieldValues.Chunk(ValueTupleFieldCountBeforeNesting).ToArray(); - var columnBindings = new ReflectionColumnBinding[dataReader.FieldCount]; + object? valueTuple = null; - for (var fieldOrdinal = 0; fieldOrdinal < dataReader.FieldCount; fieldOrdinal++) + // Now we create the nested value tuples from the inside out, by walking both arrays from their last entry + // to their first one. When we are done valueTuple contains the outermost value tuple. + for (var chunkIndex = fieldValueChunks.Length - 1; chunkIndex >= 0; chunkIndex--) { - var dataReaderFieldName = dataReaderFieldNames[fieldOrdinal]; - var dataReaderFieldType = dataReaderFieldTypes[fieldOrdinal]; - var targetType = valueTupleFieldTypes[fieldOrdinal]; - - columnBindings[fieldOrdinal] = new ReflectionColumnBinding( - GetColumnNameOrPosition(fieldOrdinal, dataReaderFieldName), - fieldOrdinal, - MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueFunction( - fieldOrdinal, - dataReaderFieldName, - dataReaderFieldType - ), - dataReaderFieldType != targetType, - targetType - ); - } - - var valueTupleConstructors = GetValueTupleConstructors(valueTupleType) - .Select(ConstructorInvoker.Create) - .ToArray(); - - return rowDataReader => - MaterializeValueTuple(rowDataReader, valueTupleType, valueTupleConstructors, columnBindings); - } + // If valueTuple is null, it means we are at the innermost value tuple, so we only need to use the + // current chunk of field values as arguments. + // + // Otherwise, if valueTuple is not null, it means we are not at the innermost value tuple, and we need to + // add valueTuple (which contains the last created inner value tuple) as the argument for the "Rest" + // parameter. + var constructorArguments = valueTuple is not null + ? [.. fieldValueChunks[chunkIndex], valueTuple] + : fieldValueChunks[chunkIndex]; - /// - /// Creates a materializer function that materializes the data in a to an instance of - /// the value tuple type . - /// - /// The type of value tuple to materialize. - /// - /// The field types of the value tuple type . - /// - /// The for which to create the materializer function. - /// - /// The names of the fields in . - /// The order of the names must match the order of the fields in . - /// - /// - /// The field types of the fields in . - /// The order of the types must match the order of the fields in . - /// - /// - /// A function that materializes the data in a to an instance of the value tuple type - /// . - /// - /// - /// Which of the two implementations builds the materializer is decided here, by - /// : the compiled expression tree when the runtime can - /// generate code, and the reflection-based materializer when it cannot. The AOT compiler folds that check to a - /// constant and removes the branch it does not need, so an application published with Native AOT does not carry - /// the expression-tree implementation at all. - /// -#if !NET9_0_OR_GREATER - // See the identical suppression in EntityMaterializerFactory.CreateMaterializer for why this is here, why it is - // a transcription of a result the net10.0 build verifies rather than an assertion, and why both target - // frameworks have to stay in the AOT warning gate. - [UnconditionalSuppressMessage( - "AOT", - "IL3050:Requires dynamic code", - Justification = "The call is inside an if (RuntimeFeature.IsDynamicCodeSupported) branch, which the AOT compiler folds " - + "to false and removes together with the expression-tree implementation. The net9.0+ analyzer " - + "recognizes that guard and reports nothing here; net8.0 lacks the [FeatureGuard] annotation on " - + "IsDynamicCodeSupported that lets it do so." - )] -#endif - private static Delegate CreateMaterializer<[DynamicallyAccessedMembers(ValueTupleMemberTypes)] TValueTuple>( - Type[] valueTupleFieldTypes, - DbDataReader dataReader, - string[] dataReaderFieldNames, - Type[] dataReaderFieldTypes - ) - { - if (RuntimeFeature.IsDynamicCodeSupported) - { - return CreateExpressionMaterializer( - valueTupleFieldTypes, - dataReader, - dataReaderFieldNames, - dataReaderFieldTypes - ); + valueTuple = valueTupleConstructors[chunkIndex].Invoke(constructorArguments.AsSpan()); } - return CreateReflectionMaterializer(dataReader, dataReaderFieldNames, dataReaderFieldTypes); + return valueTuple!; } /// @@ -525,6 +516,67 @@ private static Delegate CreateExpressionMaterializer< return Expression.Lambda(newExpression!, dataReaderParameterExpression).Compile(); } + /// + /// Creates a materializer function that materializes the data in a to an instance of + /// the value tuple type . + /// + /// The type of value tuple to materialize. + /// + /// The field types of the value tuple type . + /// + /// The for which to create the materializer function. + /// + /// The names of the fields in . + /// The order of the names must match the order of the fields in . + /// + /// + /// The field types of the fields in . + /// The order of the types must match the order of the fields in . + /// + /// + /// A function that materializes the data in a to an instance of the value tuple type + /// . + /// + /// + /// Which of the two implementations builds the materializer is decided here, by + /// : the compiled expression tree when the runtime can + /// generate code, and the reflection-based materializer when it cannot. The AOT compiler folds that check to a + /// constant and removes the branch it does not need, so an application published with Native AOT does not carry + /// the expression-tree implementation at all. + /// +#if !NET9_0_OR_GREATER + // See the identical suppression in EntityMaterializerFactory.CreateMaterializer for why this is here, why it is + // a transcription of a result the net10.0 build verifies rather than an assertion, and why both target + // frameworks have to stay in the AOT warning gate. + [UnconditionalSuppressMessage( + "AOT", + "IL3050:Requires dynamic code", + Justification = "The call is inside an if (RuntimeFeature.IsDynamicCodeSupported) branch, which the AOT compiler folds " + + "to false and removes together with the expression-tree implementation. The net9.0+ analyzer " + + "recognizes that guard and reports nothing here; net8.0 lacks the [FeatureGuard] annotation on " + + "IsDynamicCodeSupported that lets it do so." + )] +#endif + private static Delegate CreateMaterializer<[DynamicallyAccessedMembers(ValueTupleMemberTypes)] TValueTuple>( + Type[] valueTupleFieldTypes, + DbDataReader dataReader, + string[] dataReaderFieldNames, + Type[] dataReaderFieldTypes + ) + { + if (RuntimeFeature.IsDynamicCodeSupported) + { + return CreateExpressionMaterializer( + valueTupleFieldTypes, + dataReader, + dataReaderFieldNames, + dataReaderFieldTypes + ); + } + + return CreateReflectionMaterializer(dataReader, dataReaderFieldNames, dataReaderFieldTypes); + } + /// /// Gets the description of the field with the ordinal that the exception /// messages refer the consumer to. @@ -620,6 +672,50 @@ private static ConstructorInfo[] GetValueTupleConstructors( return [.. valueTupleConstructors]; } + /// + /// + /// Gets the types of the fields of the value tuple type including the fields + /// of all nested value tuple types. + /// + /// + /// For example, for the value tuple type + /// ]]> this method returns the types + /// T1, T2, T3, T4, T5, T6, T7, T8, T9. + /// + /// + /// The value tuple type of which to get the field types. + /// + /// An array containing the types of the fields of the value tuple type + /// including the fields of all nested value tuple types. + /// + private static Type[] GetValueTupleFieldTypes( + [DynamicallyAccessedMembers(ValueTupleMemberTypes)] Type valueTupleType + ) + { + var fieldTypes = new List(); + var currentValueTupleType = valueTupleType; + + while (true) + { + // The generic arguments of a value tuple type ARE its field types, in field order. + var genericArguments = currentValueTupleType.GetGenericArguments(); + + var hasNestedValueTuple = genericArguments.Length > ValueTupleFieldCountBeforeNesting; + + if (!hasNestedValueTuple) + { + fieldTypes.AddRange(genericArguments); + break; + } + + fieldTypes.AddRange(genericArguments.Take(ValueTupleFieldCountBeforeNesting)); + + currentValueTupleType = genericArguments[^1]; + } + + return [.. fieldTypes]; + } + /// /// Materializes the current row of to an instance of the value tuple type /// . @@ -656,87 +752,6 @@ ReflectionColumnBinding[] columnBindings return (TValueTuple)ConstructValueTuple(valueTupleConstructors, fieldValues); } - /// - /// Reads all fields of the current row of , in the order of the result set. - /// - /// The to read the current row of. - /// - /// The type of value tuple being materialized. Used in the exception messages. - /// - /// The fields of the result set, in the order of the fields of the value tuple. - /// - /// The field values, in the order of the result set and therefore in the order of the fields of the value tuple, - /// each one ready to be passed to the constructor of the value tuple that holds it. - /// - /// - /// A field of the result set could not be assigned to the corresponding field of the value tuple. - /// - private static object?[] ReadFieldValues( - DbDataReader dataReader, - Type valueTupleType, - ReflectionColumnBinding[] columnBindings - ) - { - var fieldValues = new object?[columnBindings.Length]; - - for (var fieldOrdinal = 0; fieldOrdinal < columnBindings.Length; fieldOrdinal++) - { - fieldValues[fieldOrdinal] = ReadFieldValue(dataReader, valueTupleType, columnBindings[fieldOrdinal]); - } - - return fieldValues; - } - - /// - /// Constructs the value tuple that holds . - /// - /// - /// The constructors of the value tuple types, from the outermost to the innermost, as returned by - /// . - /// - /// - /// The value of every field of the value tuple, including the fields of all nested value tuples, in the order in - /// which the fields are declared. - /// - /// The constructed value tuple, boxed. - /// - /// This does the same as the tail of , which builds the - /// same nesting out of instead of constructing it. - /// - private static object ConstructValueTuple(ConstructorInvoker[] valueTupleConstructors, object?[] fieldValues) - { - // In C# value tuples with more than 7 fields are represented as nested value tuples. - // E.g. a ValueTuple with 15 fields is represented as: - // ValueTuple>> - // In this case we need to create the nested value tuples from the inside out. - - // So we chunk the field values into groups of 7, which gives us the field values of one of those value - // tuples per chunk. The chunks are in the same order as valueTupleConstructors: the first chunk and the - // first constructor belong to the outermost value tuple, the last ones to the innermost value tuple. - var fieldValueChunks = fieldValues.Chunk(ValueTupleFieldCountBeforeNesting).ToArray(); - - object? valueTuple = null; - - // Now we create the nested value tuples from the inside out, by walking both arrays from their last entry - // to their first one. When we are done valueTuple contains the outermost value tuple. - for (var chunkIndex = fieldValueChunks.Length - 1; chunkIndex >= 0; chunkIndex--) - { - // If valueTuple is null, it means we are at the innermost value tuple, so we only need to use the - // current chunk of field values as arguments. - // - // Otherwise, if valueTuple is not null, it means we are not at the innermost value tuple, and we need to - // add valueTuple (which contains the last created inner value tuple) as the argument for the "Rest" - // parameter. - var constructorArguments = valueTuple is not null - ? [.. fieldValueChunks[chunkIndex], valueTuple] - : fieldValueChunks[chunkIndex]; - - valueTuple = valueTupleConstructors[chunkIndex].Invoke(constructorArguments.AsSpan()); - } - - return valueTuple!; - } - /// /// Reads the value of the field described by from the current row of /// , converting it to the type of the value tuple field it is assigned to. @@ -805,47 +820,34 @@ ReflectionColumnBinding columnBinding } /// - /// - /// Gets the types of the fields of the value tuple type including the fields - /// of all nested value tuple types. - /// - /// - /// For example, for the value tuple type - /// ]]> this method returns the types - /// T1, T2, T3, T4, T5, T6, T7, T8, T9. - /// + /// Reads all fields of the current row of , in the order of the result set. /// - /// The value tuple type of which to get the field types. + /// The to read the current row of. + /// + /// The type of value tuple being materialized. Used in the exception messages. + /// + /// The fields of the result set, in the order of the fields of the value tuple. /// - /// An array containing the types of the fields of the value tuple type - /// including the fields of all nested value tuple types. + /// The field values, in the order of the result set and therefore in the order of the fields of the value tuple, + /// each one ready to be passed to the constructor of the value tuple that holds it. /// - private static Type[] GetValueTupleFieldTypes( - [DynamicallyAccessedMembers(ValueTupleMemberTypes)] Type valueTupleType + /// + /// A field of the result set could not be assigned to the corresponding field of the value tuple. + /// + private static object?[] ReadFieldValues( + DbDataReader dataReader, + Type valueTupleType, + ReflectionColumnBinding[] columnBindings ) { - var fieldTypes = new List(); - var currentValueTupleType = valueTupleType; + var fieldValues = new object?[columnBindings.Length]; - while (true) + for (var fieldOrdinal = 0; fieldOrdinal < columnBindings.Length; fieldOrdinal++) { - // The generic arguments of a value tuple type ARE its field types, in field order. - var genericArguments = currentValueTupleType.GetGenericArguments(); - - var hasNestedValueTuple = genericArguments.Length > ValueTupleFieldCountBeforeNesting; - - if (!hasNestedValueTuple) - { - fieldTypes.AddRange(genericArguments); - break; - } - - fieldTypes.AddRange(genericArguments.Take(ValueTupleFieldCountBeforeNesting)); - - currentValueTupleType = genericArguments[^1]; + fieldValues[fieldOrdinal] = ReadFieldValue(dataReader, valueTupleType, columnBindings[fieldOrdinal]); } - return [.. fieldTypes]; + return fieldValues; } /// @@ -945,8 +947,6 @@ Type[] dataReaderFieldTypes } } - private static readonly ConcurrentDictionary materializerCache = []; - /// /// A cache key used to uniquely identify a value tuple materializer. /// @@ -965,15 +965,19 @@ private readonly struct MaterializerCacheKey( Type[] dataReaderFieldTypes ) : IEquatable { + private string[] DataReaderFieldNames { get; } = dataReaderFieldNames; + private Type[] DataReaderFieldTypes { get; } = dataReaderFieldTypes; + private Type[] ValueTupleFieldTypes { get; } = valueTupleFieldTypes; + + /// + public override bool Equals(object? obj) => obj is MaterializerCacheKey other && this.Equals(other); + /// public bool Equals(MaterializerCacheKey other) => this.ValueTupleFieldTypes.SequenceEqual(other.ValueTupleFieldTypes) && this.DataReaderFieldNames.SequenceEqual(other.DataReaderFieldNames) && this.DataReaderFieldTypes.SequenceEqual(other.DataReaderFieldTypes); - /// - public override bool Equals(object? obj) => obj is MaterializerCacheKey other && this.Equals(other); - /// public override int GetHashCode() { @@ -996,10 +1000,6 @@ public override int GetHashCode() return hashCode.ToHashCode(); } - - private string[] DataReaderFieldNames { get; } = dataReaderFieldNames; - private Type[] DataReaderFieldTypes { get; } = dataReaderFieldTypes; - private Type[] ValueTupleFieldTypes { get; } = valueTupleFieldTypes; } /// diff --git a/src/DbConnectionPlus/Readers/CommandDisposingDataReaderDecorator.cs b/src/DbConnectionPlus/Readers/CommandDisposingDataReaderDecorator.cs index 7902295..5e74f33 100644 --- a/src/DbConnectionPlus/Readers/CommandDisposingDataReaderDecorator.cs +++ b/src/DbConnectionPlus/Readers/CommandDisposingDataReaderDecorator.cs @@ -12,6 +12,12 @@ namespace RentADeveloper.DbConnectionPlus.Readers; /// internal sealed class CommandDisposingDataReaderDecorator : DbDataReader { + private readonly CancellationToken commandCancellationToken; + private readonly DbCommandDisposer commandDisposer; + private readonly DbDataReader dataReader; + private readonly IDatabaseAdapter databaseAdapter; + private bool isDisposed; + /// /// Initializes a new instance of the class. /// @@ -70,16 +76,16 @@ CancellationToken commandCancellationToken public override bool IsClosed => this.dataReader.IsClosed; /// - public override object this[int ordinal] => this.dataReader[ordinal]; + public override int RecordsAffected => this.dataReader.RecordsAffected; /// - public override object this[string name] => this.dataReader[name]; + public override int VisibleFieldCount => this.dataReader.VisibleFieldCount; /// - public override int RecordsAffected => this.dataReader.RecordsAffected; + public override object this[int ordinal] => this.dataReader[ordinal]; /// - public override int VisibleFieldCount => this.dataReader.VisibleFieldCount; + public override object this[string name] => this.dataReader[name]; /// public override void Close() => this.dataReader.Close(); @@ -290,10 +296,4 @@ protected override void Dispose(bool disposing) this.commandDisposer.Dispose(); } } - - private readonly CancellationToken commandCancellationToken; - private readonly DbCommandDisposer commandDisposer; - private readonly IDatabaseAdapter databaseAdapter; - private readonly DbDataReader dataReader; - private bool isDisposed; } diff --git a/src/DbConnectionPlus/Readers/EnumerableReader.cs b/src/DbConnectionPlus/Readers/EnumerableReader.cs index 43c95bf..9714033 100644 --- a/src/DbConnectionPlus/Readers/EnumerableReader.cs +++ b/src/DbConnectionPlus/Readers/EnumerableReader.cs @@ -21,6 +21,21 @@ namespace RentADeveloper.DbConnectionPlus.Readers; /// internal sealed class EnumerableReader : DbDataReader { + private readonly IEnumerator enumerator; + private readonly string[] fieldNames; + private readonly EnumerableReaderOptions options; + private readonly EntityPropertyMetadata[] properties; + + [DynamicallyAccessedMembers( + DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties + )] + private readonly Type? valuesType; + + private object? current; + private bool isClosed; + private bool isDisposed; + private bool isEnumeratorDisposed; + /// /// Initializes a new instance of the class that reads a single column, where /// each element of is the value of that column. @@ -151,13 +166,28 @@ EnumerableReaderOptions options public override bool IsClosed => this.isClosed; /// - public override object this[int ordinal] => this.GetValue(ordinal); + public override int RecordsAffected => -1; + + /// + /// Gets a value indicating whether the reader reads a single column whose value is the sequence element itself. + /// + private bool IsSingleColumn => this.valuesType is not null; + + /// + /// Gets a value indicating whether the reader returns values as . + /// + private bool ReadsCharsAsStrings => this.options.HasFlag(EnumerableReaderOptions.ReadCharsAsStrings); + + /// + /// Gets a value indicating whether the reader serializes values while reading them. + /// + private bool SerializesEnums => this.options.HasFlag(EnumerableReaderOptions.SerializeEnums); /// - public override object this[string name] => this.GetValue(this.GetOrdinalOrThrow(name)); + public override object this[int ordinal] => this.GetValue(ordinal); /// - public override int RecordsAffected => -1; + public override object this[string name] => this.GetValue(this.GetOrdinalOrThrow(name)); /// public override void Close() @@ -410,204 +440,6 @@ protected override void Dispose(bool disposing) } } - /// - /// Gets a value indicating whether the reader reads a single column whose value is the sequence element itself. - /// - private bool IsSingleColumn => this.valuesType is not null; - - /// - /// Gets a value indicating whether the reader returns values as . - /// - private bool ReadsCharsAsStrings => this.options.HasFlag(EnumerableReaderOptions.ReadCharsAsStrings); - - /// - /// Gets a value indicating whether the reader serializes values while reading them. - /// - private bool SerializesEnums => this.options.HasFlag(EnumerableReaderOptions.SerializeEnums); - - /// - /// Disposes the enumerator obtained from the enumerable. - /// - private void DisposeEnumerator() - { - if (this.isEnumeratorDisposed) - { - return; - } - - this.isEnumeratorDisposed = true; - (this.enumerator as IDisposable)?.Dispose(); - } - - /// - /// Throws if the specified ordinal is not one of the ordinals the reader supports. - /// - /// The ordinal to check. - /// - /// The specified ordinal is not one of the ordinals the reader supports. - /// - private void EnsureValidFieldOrdinal(int ordinal) - { - if (ordinal >= 0 && ordinal < this.FieldCount) - { - return; - } - - throw new ArgumentOutOfRangeException( - nameof(ordinal), - ordinal, - this.IsSingleColumn - ? $"The specified ordinal {ordinal} is not supported. The only supported ordinal is zero." - : $"The specified ordinal {ordinal} is not supported. The supported ordinals are 0 to " - + $"{this.FieldCount - 1}." - ); - } - - /// - /// Gets the type of the values the column with the specified ordinal reads. - /// - /// The ordinal of the column to inspect. - /// - /// The type passed to the constructor if the reader reads a single column; otherwise the type of the property - /// the column is mapped to. - /// - private Type GetColumnType(int ordinal) => this.valuesType ?? this.properties[ordinal].PropertyType; - - /// - /// Resolves the ordinal of the specified field name, throwing when the reader does not have such a field. - /// - /// The field name to resolve. - /// The ordinal of the field with the specified name. - /// - /// The reader does not have a field with the specified name . - /// - private int GetOrdinalOrThrow(string name) - { - var ordinal = Array.IndexOf(this.fieldNames, name); - - if (ordinal >= 0) - { - return ordinal; - } - - throw new ArgumentOutOfRangeException( - nameof(name), - this.IsSingleColumn - ? $"The specified field name '{name}' is not supported. The only supported field name is " - + $"'{this.fieldNames[0]}'." - : $"The specified field name '{name}' is not supported. The supported field names are " - + $"'{string.Join("', '", this.fieldNames)}'." - ); - } - - /// - /// Determines whether the column with the specified ordinal is mapped to an property. - /// - /// The ordinal of the column to inspect. - /// - /// if the column is mapped to an property; otherwise, - /// . - /// - private bool IsEnumColumn(int ordinal) => this.GetColumnType(ordinal).IsEnumOrNullableEnumType(); - - /// - /// Applies the reader's to a value that was read from an entity. - /// - /// The value to serialize. - /// The serialized value. - private object SerializeValue(object value) - { - if (this.SerializesEnums && value is Enum enumValue) - { - return EnumSerializer.SerializeEnum( - enumValue, - DbConnectionPlusConfiguration.Instance.EnumSerializationMode - ); - } - - if (this.ReadsCharsAsStrings && value is char charValue) - { - // The data readers of all major database systems return the type String for CHAR columns. - // So we mimic the same behavior for consistency. - - return charValue.ToString(); - } - - return value; - } - - /// - /// Resolves the type a column is reported as from the type of the property it is mapped to. - /// - /// The type of the property the column is mapped to. - /// The behaviours the reader applies to the values it reads. - /// The type the column is reported as. - /// - /// The configured is not a defined value. - /// - /// - /// Every branch returns a typeof literal so that the value satisfies the - /// the base class puts on - /// ; see the remarks there. A type that is neither a supported built-in - /// type nor covered by — an outside MySQL, most notably — is - /// reported as . Returning the runtime property type would violate the inherited trimming - /// contract because PropertyInfo.PropertyType carries no member annotation. No caller inside this library - /// reads that fallback: PostgreSqlTemporaryTableBuilder, the one place that would inspect the reader's - /// field types, derives its NpgsqlDbType values from the entity metadata instead. - /// - [return: DynamicallyAccessedMembers( - DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties - )] - private static Type MapReportedFieldType(Type propertyType, EnumerableReaderOptions options) - { - if (propertyType.IsEnumOrNullableEnumType()) - { - if (!options.HasFlag(EnumerableReaderOptions.SerializeEnums)) - { - return typeof(object); - } - - var enumSerializationMode = DbConnectionPlusConfiguration.Instance.EnumSerializationMode; - - return enumSerializationMode switch - { - EnumSerializationMode.Strings => typeof(string), - - EnumSerializationMode.Integers => typeof(int), - - _ => ThrowInvalidEnumSerializationModeException(enumSerializationMode), - }; - } - - if (propertyType.IsCharOrNullableCharType() && options.HasFlag(EnumerableReaderOptions.ReadCharsAsStrings)) - { - // The data readers of all major database systems return the type String for CHAR columns. - // So we mimic the same behavior for consistency. - - return typeof(string); - } - - return MapBuiltInFieldType(Nullable.GetUnderlyingType(propertyType) ?? propertyType); - } - - /// - /// Throws an indicating that the specified - /// is invalid. - /// - /// The value that is invalid. - /// This method never returns. - /// Always thrown. - [DoesNotReturn] - [return: DynamicallyAccessedMembers( - DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties - )] - private static Type ThrowInvalidEnumSerializationModeException(EnumSerializationMode enumSerializationMode) => - throw new ArgumentOutOfRangeException( - nameof(enumSerializationMode), - enumSerializationMode, - $"The {nameof(EnumSerializationMode)} {enumSerializationMode.ToDebugString()} is not supported." - ); - /// /// Maps a non-nullable property type onto the statically known the column is reported as. /// @@ -744,17 +576,186 @@ private static Type MapBuiltInFieldType(Type propertyType) return typeof(object); } - private readonly IEnumerator enumerator; - private readonly string[] fieldNames; - private readonly EnumerableReaderOptions options; - private readonly EntityPropertyMetadata[] properties; + /// + /// Resolves the type a column is reported as from the type of the property it is mapped to. + /// + /// The type of the property the column is mapped to. + /// The behaviours the reader applies to the values it reads. + /// The type the column is reported as. + /// + /// The configured is not a defined value. + /// + /// + /// Every branch returns a typeof literal so that the value satisfies the + /// the base class puts on + /// ; see the remarks there. A type that is neither a supported built-in + /// type nor covered by — an outside MySQL, most notably — is + /// reported as . Returning the runtime property type would violate the inherited trimming + /// contract because PropertyInfo.PropertyType carries no member annotation. No caller inside this library + /// reads that fallback: PostgreSqlTemporaryTableBuilder, the one place that would inspect the reader's + /// field types, derives its NpgsqlDbType values from the entity metadata instead. + /// + [return: DynamicallyAccessedMembers( + DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties + )] + private static Type MapReportedFieldType(Type propertyType, EnumerableReaderOptions options) + { + if (propertyType.IsEnumOrNullableEnumType()) + { + if (!options.HasFlag(EnumerableReaderOptions.SerializeEnums)) + { + return typeof(object); + } - [DynamicallyAccessedMembers( + var enumSerializationMode = DbConnectionPlusConfiguration.Instance.EnumSerializationMode; + + return enumSerializationMode switch + { + EnumSerializationMode.Strings => typeof(string), + + EnumSerializationMode.Integers => typeof(int), + + _ => ThrowInvalidEnumSerializationModeException(enumSerializationMode), + }; + } + + if (propertyType.IsCharOrNullableCharType() && options.HasFlag(EnumerableReaderOptions.ReadCharsAsStrings)) + { + // The data readers of all major database systems return the type String for CHAR columns. + // So we mimic the same behavior for consistency. + + return typeof(string); + } + + return MapBuiltInFieldType(Nullable.GetUnderlyingType(propertyType) ?? propertyType); + } + + /// + /// Throws an indicating that the specified + /// is invalid. + /// + /// The value that is invalid. + /// This method never returns. + /// Always thrown. + [DoesNotReturn] + [return: DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties )] - private readonly Type? valuesType; - private object? current; - private bool isClosed; - private bool isDisposed; - private bool isEnumeratorDisposed; + private static Type ThrowInvalidEnumSerializationModeException(EnumSerializationMode enumSerializationMode) => + throw new ArgumentOutOfRangeException( + nameof(enumSerializationMode), + enumSerializationMode, + $"The {nameof(EnumSerializationMode)} {enumSerializationMode.ToDebugString()} is not supported." + ); + + /// + /// Disposes the enumerator obtained from the enumerable. + /// + private void DisposeEnumerator() + { + if (this.isEnumeratorDisposed) + { + return; + } + + this.isEnumeratorDisposed = true; + (this.enumerator as IDisposable)?.Dispose(); + } + + /// + /// Throws if the specified ordinal is not one of the ordinals the reader supports. + /// + /// The ordinal to check. + /// + /// The specified ordinal is not one of the ordinals the reader supports. + /// + private void EnsureValidFieldOrdinal(int ordinal) + { + if (ordinal >= 0 && ordinal < this.FieldCount) + { + return; + } + + throw new ArgumentOutOfRangeException( + nameof(ordinal), + ordinal, + this.IsSingleColumn + ? $"The specified ordinal {ordinal} is not supported. The only supported ordinal is zero." + : $"The specified ordinal {ordinal} is not supported. The supported ordinals are 0 to " + + $"{this.FieldCount - 1}." + ); + } + + /// + /// Gets the type of the values the column with the specified ordinal reads. + /// + /// The ordinal of the column to inspect. + /// + /// The type passed to the constructor if the reader reads a single column; otherwise the type of the property + /// the column is mapped to. + /// + private Type GetColumnType(int ordinal) => this.valuesType ?? this.properties[ordinal].PropertyType; + + /// + /// Resolves the ordinal of the specified field name, throwing when the reader does not have such a field. + /// + /// The field name to resolve. + /// The ordinal of the field with the specified name. + /// + /// The reader does not have a field with the specified name . + /// + private int GetOrdinalOrThrow(string name) + { + var ordinal = Array.IndexOf(this.fieldNames, name); + + if (ordinal >= 0) + { + return ordinal; + } + + throw new ArgumentOutOfRangeException( + nameof(name), + this.IsSingleColumn + ? $"The specified field name '{name}' is not supported. The only supported field name is " + + $"'{this.fieldNames[0]}'." + : $"The specified field name '{name}' is not supported. The supported field names are " + + $"'{string.Join("', '", this.fieldNames)}'." + ); + } + + /// + /// Determines whether the column with the specified ordinal is mapped to an property. + /// + /// The ordinal of the column to inspect. + /// + /// if the column is mapped to an property; otherwise, + /// . + /// + private bool IsEnumColumn(int ordinal) => this.GetColumnType(ordinal).IsEnumOrNullableEnumType(); + + /// + /// Applies the reader's to a value that was read from an entity. + /// + /// The value to serialize. + /// The serialized value. + private object SerializeValue(object value) + { + if (this.SerializesEnums && value is Enum enumValue) + { + return EnumSerializer.SerializeEnum( + enumValue, + DbConnectionPlusConfiguration.Instance.EnumSerializationMode + ); + } + + if (this.ReadsCharsAsStrings && value is char charValue) + { + // The data readers of all major database systems return the type String for CHAR columns. + // So we mimic the same behavior for consistency. + + return charValue.ToString(); + } + + return value; + } } diff --git a/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatement.cs b/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatement.cs index 52fe83b..08196f8 100644 --- a/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatement.cs +++ b/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatement.cs @@ -22,6 +22,9 @@ namespace RentADeveloper.DbConnectionPlus.SqlStatements; // ReSharper disable once StructCanBeMadeReadOnly public struct InterpolatedSqlStatement : IEquatable { + private readonly List fragments; + private readonly List temporaryTables; + /// /// Initializes a new instance of the class. /// @@ -102,92 +105,68 @@ public InterpolatedSqlStatement(string code, params (string Name, object? Value) } /// - /// Appends the specified value to this instance. + /// The fragments that make up this SQL statement. /// - /// The type of value to append. - /// The value to append. - /// - /// The minimum number of characters that should be written for . - /// A negative value indicates that the value should be left-aligned and the required minimum whitespace characters - /// to add is the absolute value. - /// - /// The string to use to format . - /// - /// This method is part of the interpolated string handler pattern. - /// It is not intended to be called by user code. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public void AppendFormatted(T? value, int alignment = 0, string? format = null) - { - switch (value) - { - case InterpolatedParameter interpolatedParameter: - this.fragments.Add(interpolatedParameter); - break; - - case InterpolatedTemporaryTable interpolatedTemporaryTable: - this.fragments.Add(interpolatedTemporaryTable); - this.temporaryTables.Add(interpolatedTemporaryTable); - break; + internal IReadOnlyList Fragments => this.fragments; - default: - var formattedValue = value switch - { - string stringValue => stringValue, - IFormattable formattable => formattable.ToString(format, CultureInfo.InvariantCulture), - null => string.Empty, - _ => value.ToString() ?? string.Empty, - }; + /// + /// The temporary tables used in this SQL statement. + /// + internal readonly IReadOnlyList TemporaryTables => this.temporaryTables; - if (alignment != 0) - { - var paddingWidth = Math.Abs(alignment); - var padding = paddingWidth - formattedValue.Length; + /// + /// Implicitly converts a string to an instance of . + /// + /// The string to convert to an instance of . + /// is . + public static implicit operator InterpolatedSqlStatement(string value) + { + ArgumentNullException.ThrowIfNull(value); - if (padding > 0) - { - if (alignment > 0) - { - // Right-align: - this.fragments.Add(new Literal(new string(' ', padding) + formattedValue)); - } - else - { - // Left-align: - this.fragments.Add(new Literal(formattedValue + new string(' ', padding))); - } + return new(value); + } - break; - } - } + /// + /// Determines whether the two specified instances of are equal. + /// + /// The first instance to compare. + /// The second instance to compare. + /// + /// if the two specified instances of are + /// equal; otherwise, . + /// + public static bool operator ==(InterpolatedSqlStatement left, InterpolatedSqlStatement right) => left.Equals(right); - this.fragments.Add(new Literal(formattedValue)); - break; - } - } + /// + /// Determines whether the two specified instances of are unequal. + /// + /// The first instance to compare. + /// The second instance to compare. + /// + /// if the two the specified instances of are + /// unequal; otherwise, . + /// + public static bool operator !=(InterpolatedSqlStatement left, InterpolatedSqlStatement right) => !(left == right); /// - /// Appends the specified literal value to this instance. + /// Creates a new instance of from the specified string. /// - /// The literal value to append to this instance. - /// - /// This method is part of the interpolated string handler pattern. - /// It is not intended to be called by user code. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public void AppendLiteral(string? value) + /// + /// The string from which to create an instance of . + /// + /// is . + public static InterpolatedSqlStatement FromString(string value) { - if (value is not null) - { - this.fragments.Add(new Literal(value)); - } + ArgumentNullException.ThrowIfNull(value); + + return new(value); } /// - public readonly bool Equals(InterpolatedSqlStatement other) => this.fragments.SequenceEqual(other.Fragments); + public override readonly bool Equals(object? obj) => obj is InterpolatedSqlStatement other && this.Equals(other); /// - public override readonly bool Equals(object? obj) => obj is InterpolatedSqlStatement other && this.Equals(other); + public readonly bool Equals(InterpolatedSqlStatement other) => this.fragments.SequenceEqual(other.Fragments); /// public override readonly int GetHashCode() @@ -298,63 +277,84 @@ public override readonly string ToString() } /// - /// Creates a new instance of from the specified string. + /// Appends the specified value to this instance. /// - /// - /// The string from which to create an instance of . + /// The type of value to append. + /// The value to append. + /// + /// The minimum number of characters that should be written for . + /// A negative value indicates that the value should be left-aligned and the required minimum whitespace characters + /// to add is the absolute value. /// - /// is . - public static InterpolatedSqlStatement FromString(string value) + /// The string to use to format . + /// + /// This method is part of the interpolated string handler pattern. + /// It is not intended to be called by user code. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void AppendFormatted(T? value, int alignment = 0, string? format = null) { - ArgumentNullException.ThrowIfNull(value); + switch (value) + { + case InterpolatedParameter interpolatedParameter: + this.fragments.Add(interpolatedParameter); + break; - return new(value); - } + case InterpolatedTemporaryTable interpolatedTemporaryTable: + this.fragments.Add(interpolatedTemporaryTable); + this.temporaryTables.Add(interpolatedTemporaryTable); + break; - /// - /// Determines whether the two specified instances of are equal. - /// - /// The first instance to compare. - /// The second instance to compare. - /// - /// if the two specified instances of are - /// equal; otherwise, . - /// - public static bool operator ==(InterpolatedSqlStatement left, InterpolatedSqlStatement right) => left.Equals(right); + default: + var formattedValue = value switch + { + string stringValue => stringValue, + IFormattable formattable => formattable.ToString(format, CultureInfo.InvariantCulture), + null => string.Empty, + _ => value.ToString() ?? string.Empty, + }; - /// - /// Implicitly converts a string to an instance of . - /// - /// The string to convert to an instance of . - /// is . - public static implicit operator InterpolatedSqlStatement(string value) - { - ArgumentNullException.ThrowIfNull(value); + if (alignment != 0) + { + var paddingWidth = Math.Abs(alignment); + var padding = paddingWidth - formattedValue.Length; - return new(value); - } + if (padding > 0) + { + if (alignment > 0) + { + // Right-align: + this.fragments.Add(new Literal(new string(' ', padding) + formattedValue)); + } + else + { + // Left-align: + this.fragments.Add(new Literal(formattedValue + new string(' ', padding))); + } - /// - /// Determines whether the two specified instances of are unequal. - /// - /// The first instance to compare. - /// The second instance to compare. - /// - /// if the two the specified instances of are - /// unequal; otherwise, . - /// - public static bool operator !=(InterpolatedSqlStatement left, InterpolatedSqlStatement right) => !(left == right); + break; + } + } - /// - /// The fragments that make up this SQL statement. - /// - internal IReadOnlyList Fragments => this.fragments; + this.fragments.Add(new Literal(formattedValue)); + break; + } + } /// - /// The temporary tables used in this SQL statement. + /// Appends the specified literal value to this instance. /// - internal readonly IReadOnlyList TemporaryTables => this.temporaryTables; - - private readonly List fragments; - private readonly List temporaryTables; + /// The literal value to append to this instance. + /// + /// This method is part of the interpolated string handler pattern. + /// It is not intended to be called by user code. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void AppendLiteral(string? value) + { + if (value is not null) + { + this.fragments.Add(new Literal(value)); + } + } } diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntitiesTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntitiesTests.cs index bfb625f..9b0d897 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntitiesTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntitiesTests.cs @@ -23,6 +23,8 @@ public abstract class EntityManipulator_DeleteEntitiesTests where TTestDatabaseProvider : ITestDatabaseProvider, new() { + private readonly IEntityManipulator manipulator; + /// protected EntityManipulator_DeleteEntitiesTests() => this.manipulator = this.DatabaseAdapter.EntityManipulator; @@ -318,6 +320,4 @@ private Task CallApi( return Task.FromException(ex); } } - - private readonly IEntityManipulator manipulator; } diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntityTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntityTests.cs index 8ece3ca..00b1476 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntityTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.DeleteEntityTests.cs @@ -23,6 +23,8 @@ public abstract class EntityManipulator_DeleteEntityTests : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { + private readonly IEntityManipulator manipulator; + /// protected EntityManipulator_DeleteEntityTests() => this.manipulator = this.DatabaseAdapter.EntityManipulator; @@ -254,6 +256,4 @@ private Task CallApi( return Task.FromException(ex); } } - - private readonly IEntityManipulator manipulator; } diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntitiesTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntitiesTests.cs index 8cc4115..a662448 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntitiesTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntitiesTests.cs @@ -22,6 +22,8 @@ public abstract class EntityManipulator_InsertEntitiesTests where TTestDatabaseProvider : ITestDatabaseProvider, new() { + private readonly IEntityManipulator manipulator; + /// protected EntityManipulator_InsertEntitiesTests() => this.manipulator = this.DatabaseAdapter.EntityManipulator; @@ -294,6 +296,4 @@ private Task CallApi( return Task.FromException(ex); } } - - private readonly IEntityManipulator manipulator; } diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntityTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntityTests.cs index 68fd430..22b127e 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntityTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.InsertEntityTests.cs @@ -22,6 +22,8 @@ public abstract class EntityManipulator_InsertEntityTests : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { + private readonly IEntityManipulator manipulator; + /// protected EntityManipulator_InsertEntityTests() => this.manipulator = this.DatabaseAdapter.EntityManipulator; @@ -257,6 +259,4 @@ private Task CallApi( return Task.FromException(ex); } } - - private readonly IEntityManipulator manipulator; } diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntitiesTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntitiesTests.cs index 30e0d5e..ab314e0 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntitiesTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntitiesTests.cs @@ -23,6 +23,8 @@ public abstract class EntityManipulator_UpdateEntitiesTests where TTestDatabaseProvider : ITestDatabaseProvider, new() { + private readonly IEntityManipulator manipulator; + /// protected EntityManipulator_UpdateEntitiesTests() => this.manipulator = this.DatabaseAdapter.EntityManipulator; @@ -514,6 +516,4 @@ private Task CallApi( return Task.FromException(ex); } } - - private readonly IEntityManipulator manipulator; } diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntityTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntityTests.cs index cb23166..67e5d25 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntityTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/EntityManipulator.UpdateEntityTests.cs @@ -23,6 +23,8 @@ public abstract class EntityManipulator_UpdateEntityTests : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { + private readonly IEntityManipulator manipulator; + /// protected EntityManipulator_UpdateEntityTests() => this.manipulator = this.DatabaseAdapter.EntityManipulator; @@ -430,6 +432,4 @@ private Task CallApi( return Task.FromException(ex); } } - - private readonly IEntityManipulator manipulator; } diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs index 3831875..624c913 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs @@ -7,6 +7,8 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.DatabaseAdapters.Orac public class OracleDatabaseAdapterTests : IntegrationTestsBase { + private readonly OracleDatabaseAdapter adapter = new(); + [Fact] public void QuoteTemporaryTableName_ShouldQuoteTableName() { @@ -45,6 +47,4 @@ public void WasSqlStatementCancelledByCancellationToken_StatementWasNotCancelled this.adapter.WasSqlStatementCancelledByCancellationToken(exception, CancellationToken.None).Should().BeFalse(); } - - private readonly OracleDatabaseAdapter adapter = new(); } diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/PostgreSql/PostgreSqlDatabaseAdapterTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/PostgreSql/PostgreSqlDatabaseAdapterTests.cs index ec98e3f..496c00b 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/PostgreSql/PostgreSqlDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/PostgreSql/PostgreSqlDatabaseAdapterTests.cs @@ -7,6 +7,8 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.DatabaseAdapters.Post public class PostgreSqlDatabaseAdapterTests : IntegrationTestsBase { + private readonly PostgreSqlDatabaseAdapter adapter = new(); + [Fact] public void SupportsTemporaryTables_ShouldReturnTrue() => this.adapter.SupportsTemporaryTables(this.Connection).Should().BeTrue(); @@ -39,6 +41,4 @@ public void WasSqlStatementCancelledByCancellationToken_StatementWasNotCancelled this.adapter.WasSqlStatementCancelledByCancellationToken(exception, CancellationToken.None).Should().BeFalse(); } - - private readonly PostgreSqlDatabaseAdapter adapter = new(); } diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/SqlServer/SqlServerDatabaseAdapterTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/SqlServer/SqlServerDatabaseAdapterTests.cs index bdcb739..28ec8a1 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/SqlServer/SqlServerDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/SqlServer/SqlServerDatabaseAdapterTests.cs @@ -6,6 +6,8 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.DatabaseAdapters.SqlS public class SqlServerDatabaseAdapterTests : IntegrationTestsBase { + private readonly SqlServerDatabaseAdapter adapter = new(); + [Fact] public void SupportsTemporaryTables_ShouldReturnTrue() => this.adapter.SupportsTemporaryTables(this.Connection).Should().BeTrue(); @@ -35,6 +37,4 @@ public void WasSqlStatementCancelledByCancellationToken_StatementWasNotCancelled this.adapter.WasSqlStatementCancelledByCancellationToken(exception, CancellationToken.None).Should().BeFalse(); } - - private readonly SqlServerDatabaseAdapter adapter = new(); } diff --git a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/TemporaryTableBuilderTests.cs b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/TemporaryTableBuilderTests.cs index 5aac6d1..3e74837 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/TemporaryTableBuilderTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DatabaseAdapters/TemporaryTableBuilderTests.cs @@ -19,6 +19,8 @@ public sealed class TemporaryTableBuilderTests_SqlServer : TemporaryTableBuilder public abstract class TemporaryTableBuilderTests : IntegrationTestsBase where TTestDatabaseProvider : ITestDatabaseProvider, new() { + private readonly ITemporaryTableBuilder builder; + /// protected TemporaryTableBuilderTests() => this.builder = this.DatabaseAdapter.TemporaryTableBuilder; @@ -347,6 +349,35 @@ await this .BeEquivalentTo(itemsWithNulls); } + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task BuildTemporaryTable_ScalarValuesWithNullValues_ShouldHandleNullValues(bool useAsyncApi) + { + var values = Generate.MultipleNullable(); + + await using var tableDisposer = await this.CallApi( + useAsyncApi, + this.Connection, + null, + "NullValues", + values, + typeof(int?), + TestContext.Current.CancellationToken + ); + + ( + await this + .Connection.QueryAsync( + $"SELECT {Q("Value")} FROM {QT("NullValues")}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) + .Should() + .BeEquivalentTo(values); + } + [Theory] [InlineData(false)] [InlineData(true)] @@ -576,35 +607,6 @@ public async Task BuildTemporaryTable_ScalarValues_ShouldUseCollationOfDatabaseF columnCollation.Should().Be(this.TestDatabaseProvider.DatabaseCollation); } - [Theory] - [InlineData(false)] - [InlineData(true)] - public async Task BuildTemporaryTable_ScalarValuesWithNullValues_ShouldHandleNullValues(bool useAsyncApi) - { - var values = Generate.MultipleNullable(); - - await using var tableDisposer = await this.CallApi( - useAsyncApi, - this.Connection, - null, - "NullValues", - values, - typeof(int?), - TestContext.Current.CancellationToken - ); - - ( - await this - .Connection.QueryAsync( - $"SELECT {Q("Value")} FROM {QT("NullValues")}", - cancellationToken: TestContext.Current.CancellationToken - ) - .ToListAsync(TestContext.Current.CancellationToken) - ) - .Should() - .BeEquivalentTo(values); - } - [Theory] [InlineData(false)] [InlineData(true)] @@ -660,6 +662,4 @@ private Task CallApi( return Task.FromException(ex); } } - - private readonly ITemporaryTableBuilder builder; } diff --git a/tests/DbConnectionPlus.IntegrationTests/DbCommands/DbCommandDisposerTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbCommands/DbCommandDisposerTests.cs index 045f3ca..d975e6e 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbCommands/DbCommandDisposerTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbCommands/DbCommandDisposerTests.cs @@ -14,33 +14,36 @@ public abstract class DbCommandDisposerTests : Integratio where TTestDatabaseProvider : ITestDatabaseProvider, new() { [Fact] - public void Dispose_AlreadyDisposed_ShouldNotAttemptToDropTemporaryTablesAgain() + public async Task DisposeAsync_AlreadyDisposed_ShouldNotAttemptToDropTemporaryTablesAgain() { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entityIds = Generate.Ids(); - InterpolatedSqlStatement statement = $"SELECT {Q("Value")} FROM {TemporaryTable(entityIds)}"; var temporaryTables = statement.TemporaryTables; - var (_, commandDisposer) = DbCommandBuilder.BuildDbCommand(statement, this.DatabaseAdapter, this.Connection); + var (_, commandDisposer) = await DbCommandBuilder.BuildDbCommandAsync( + statement, + this.DatabaseAdapter, + this.Connection + ); this.ExistsTemporaryTableInDb(temporaryTables[0].Name).Should().BeTrue(); - commandDisposer.Dispose(); + await commandDisposer.DisposeAsync(); this.ExistsTemporaryTableInDb(temporaryTables[0].Name).Should().BeFalse(); - Invoking(() => commandDisposer.Dispose()).Should().NotThrow(); + await Invoking(() => commandDisposer.DisposeAsync().AsTask()).Should().NotThrowAsync(); - Invoking(() => commandDisposer.Dispose()).Should().NotThrow(); + await Invoking(() => commandDisposer.DisposeAsync().AsTask()).Should().NotThrowAsync(); - Invoking(() => commandDisposer.Dispose()).Should().NotThrow(); + await Invoking(() => commandDisposer.DisposeAsync().AsTask()).Should().NotThrowAsync(); } [Fact] - public void Dispose_ShouldDropTemporaryTables() + public async Task DisposeAsync_ShouldDisposeTemporaryTables() { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -55,50 +58,47 @@ public void Dispose_ShouldDropTemporaryTables() var temporaryTables = statement.TemporaryTables; - var (_, commandDisposer) = DbCommandBuilder.BuildDbCommand(statement, this.DatabaseAdapter, this.Connection); + var (_, commandDisposer) = await DbCommandBuilder.BuildDbCommandAsync( + statement, + this.DatabaseAdapter, + this.Connection + ); this.ExistsTemporaryTableInDb(temporaryTables[0].Name).Should().BeTrue(); - this.ExistsTemporaryTableInDb(temporaryTables[1].Name).Should().BeTrue(); - - commandDisposer.Dispose(); + await commandDisposer.DisposeAsync(); this.ExistsTemporaryTableInDb(temporaryTables[0].Name).Should().BeFalse(); - - this.ExistsTemporaryTableInDb(temporaryTables[1].Name).Should().BeFalse(); } [Fact] - public async Task DisposeAsync_AlreadyDisposed_ShouldNotAttemptToDropTemporaryTablesAgain() + public void Dispose_AlreadyDisposed_ShouldNotAttemptToDropTemporaryTablesAgain() { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entityIds = Generate.Ids(); + InterpolatedSqlStatement statement = $"SELECT {Q("Value")} FROM {TemporaryTable(entityIds)}"; var temporaryTables = statement.TemporaryTables; - var (_, commandDisposer) = await DbCommandBuilder.BuildDbCommandAsync( - statement, - this.DatabaseAdapter, - this.Connection - ); + var (_, commandDisposer) = DbCommandBuilder.BuildDbCommand(statement, this.DatabaseAdapter, this.Connection); this.ExistsTemporaryTableInDb(temporaryTables[0].Name).Should().BeTrue(); - await commandDisposer.DisposeAsync(); + commandDisposer.Dispose(); this.ExistsTemporaryTableInDb(temporaryTables[0].Name).Should().BeFalse(); - await Invoking(() => commandDisposer.DisposeAsync().AsTask()).Should().NotThrowAsync(); + Invoking(() => commandDisposer.Dispose()).Should().NotThrow(); - await Invoking(() => commandDisposer.DisposeAsync().AsTask()).Should().NotThrowAsync(); + Invoking(() => commandDisposer.Dispose()).Should().NotThrow(); - await Invoking(() => commandDisposer.DisposeAsync().AsTask()).Should().NotThrowAsync(); + Invoking(() => commandDisposer.Dispose()).Should().NotThrow(); } [Fact] - public async Task DisposeAsync_ShouldDisposeTemporaryTables() + public void Dispose_ShouldDropTemporaryTables() { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -113,16 +113,16 @@ public async Task DisposeAsync_ShouldDisposeTemporaryTables() var temporaryTables = statement.TemporaryTables; - var (_, commandDisposer) = await DbCommandBuilder.BuildDbCommandAsync( - statement, - this.DatabaseAdapter, - this.Connection - ); + var (_, commandDisposer) = DbCommandBuilder.BuildDbCommand(statement, this.DatabaseAdapter, this.Connection); this.ExistsTemporaryTableInDb(temporaryTables[0].Name).Should().BeTrue(); - await commandDisposer.DisposeAsync(); + this.ExistsTemporaryTableInDb(temporaryTables[1].Name).Should().BeTrue(); + + commandDisposer.Dispose(); this.ExistsTemporaryTableInDb(temporaryTables[0].Name).Should().BeFalse(); + + this.ExistsTemporaryTableInDb(temporaryTables[1].Name).Should().BeFalse(); } } diff --git a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.TemporaryTableTests.cs b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.TemporaryTableTests.cs index 6b48a3d..677235a 100644 --- a/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.TemporaryTableTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/DbConnectionExtensions.TemporaryTableTests.cs @@ -17,7 +17,7 @@ public abstract class DbConnectionExtensions_TemporaryTableTests(); - this.Connection.Query( - $"SELECT {Q("Enum")} FROM {TemporaryTable(entities)}", - cancellationToken: TestContext.Current.CancellationToken - ) + ( + await this + .Connection.QueryAsync( + $"SELECT {Q("Enum")} FROM {TemporaryTable(entities)}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) .Should() .BeEquivalentTo(entities.Select(a => (int)a.Enum)); } [Fact] - public void TemporaryTable_ComplexObjects_EnumProperty_EnumSerializationModeIsStrings_ShouldSerializeEnumToString() + public async Task TemporaryTableAsync_ComplexObjects_EnumProperty_EnumSerializationModeIsStrings_ShouldSerializeEnumToString() { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -42,31 +46,39 @@ public void TemporaryTable_ComplexObjects_EnumProperty_EnumSerializationModeIsSt var entities = Generate.Multiple(); - this.Connection.Query( - $"SELECT {Q("Enum")} FROM {TemporaryTable(entities)}", - cancellationToken: TestContext.Current.CancellationToken - ) + ( + await this + .Connection.QueryAsync( + $"SELECT {Q("Enum")} FROM {TemporaryTable(entities)}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) .Should() .BeEquivalentTo(entities.Select(a => a.Enum.ToString())); } [Fact] - public void TemporaryTable_ComplexObjects_ShouldBePassedAsMultiColumnTemporaryTableToSqlStatement() + public async Task TemporaryTableAsync_ComplexObjects_ShouldBePassedAsMultiColumnTemporaryTableToSqlStatement() { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entities = Generate.Multiple(); - this.Connection.Query( - $"SELECT * FROM {TemporaryTable(entities)}", - cancellationToken: TestContext.Current.CancellationToken - ) + ( + await this + .Connection.QueryAsync( + $"SELECT * FROM {TemporaryTable(entities)}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) .Should() .BeEquivalentTo(entities); } [Fact] - public void TemporaryTable_ScalarValues_Enums_EnumSerializationModeIsIntegers_ShouldSerializeEnumToInteger() + public async Task TemporaryTableAsync_ScalarValues_Enums_EnumSerializationModeIsIntegers_ShouldSerializeEnumToInteger() { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -74,16 +86,20 @@ public void TemporaryTable_ScalarValues_Enums_EnumSerializationModeIsIntegers_Sh var enumValues = Generate.Multiple(); - this.Connection.Query( - $"SELECT {Q("Value")} FROM {TemporaryTable(enumValues)}", - cancellationToken: TestContext.Current.CancellationToken - ) + ( + await this + .Connection.QueryAsync( + $"SELECT {Q("Value")} FROM {TemporaryTable(enumValues)}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) .Should() .BeEquivalentTo(enumValues.Select(a => (int)a)); } [Fact] - public void TemporaryTable_ScalarValues_Enums_EnumSerializationModeIsStrings_ShouldSerializeEnumToString() + public async Task TemporaryTableAsync_ScalarValues_Enums_EnumSerializationModeIsStrings_ShouldSerializeEnumToString() { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -91,31 +107,39 @@ public void TemporaryTable_ScalarValues_Enums_EnumSerializationModeIsStrings_Sho var enumValues = Generate.Multiple(); - this.Connection.Query( - $"SELECT {Q("Value")} FROM {TemporaryTable(enumValues)}", - cancellationToken: TestContext.Current.CancellationToken - ) + ( + await this + .Connection.QueryAsync( + $"SELECT {Q("Value")} FROM {TemporaryTable(enumValues)}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) .Should() .BeEquivalentTo(enumValues.Select(a => a.ToString())); } [Fact] - public void TemporaryTable_ScalarValues_ShouldBePassedAsSingleColumnTemporaryTableToSqlStatement() + public async Task TemporaryTableAsync_ScalarValues_ShouldBePassedAsSingleColumnTemporaryTableToSqlStatement() { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entityIds = Generate.Ids(); - this.Connection.Query( - $"SELECT {Q("Value")} FROM {TemporaryTable(entityIds)}", - cancellationToken: TestContext.Current.CancellationToken - ) + ( + await this + .Connection.QueryAsync( + $"SELECT {Q("Value")} FROM {TemporaryTable(entityIds)}", + cancellationToken: TestContext.Current.CancellationToken + ) + .ToListAsync(TestContext.Current.CancellationToken) + ) .Should() .BeEquivalentTo(entityIds); } [Fact] - public async Task TemporaryTableAsync_ComplexObjects_EnumProperty_EnumSerializationModeIsIntegers_ShouldSerializeEnumToInteger() + public void TemporaryTable_ComplexObjects_EnumProperty_EnumSerializationModeIsIntegers_ShouldSerializeEnumToInteger() { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -123,20 +147,16 @@ public async Task TemporaryTableAsync_ComplexObjects_EnumProperty_EnumSerializat var entities = Generate.Multiple(); - ( - await this - .Connection.QueryAsync( - $"SELECT {Q("Enum")} FROM {TemporaryTable(entities)}", - cancellationToken: TestContext.Current.CancellationToken - ) - .ToListAsync(TestContext.Current.CancellationToken) - ) + this.Connection.Query( + $"SELECT {Q("Enum")} FROM {TemporaryTable(entities)}", + cancellationToken: TestContext.Current.CancellationToken + ) .Should() .BeEquivalentTo(entities.Select(a => (int)a.Enum)); } [Fact] - public async Task TemporaryTableAsync_ComplexObjects_EnumProperty_EnumSerializationModeIsStrings_ShouldSerializeEnumToString() + public void TemporaryTable_ComplexObjects_EnumProperty_EnumSerializationModeIsStrings_ShouldSerializeEnumToString() { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -144,39 +164,31 @@ public async Task TemporaryTableAsync_ComplexObjects_EnumProperty_EnumSerializat var entities = Generate.Multiple(); - ( - await this - .Connection.QueryAsync( - $"SELECT {Q("Enum")} FROM {TemporaryTable(entities)}", - cancellationToken: TestContext.Current.CancellationToken - ) - .ToListAsync(TestContext.Current.CancellationToken) - ) + this.Connection.Query( + $"SELECT {Q("Enum")} FROM {TemporaryTable(entities)}", + cancellationToken: TestContext.Current.CancellationToken + ) .Should() .BeEquivalentTo(entities.Select(a => a.Enum.ToString())); } [Fact] - public async Task TemporaryTableAsync_ComplexObjects_ShouldBePassedAsMultiColumnTemporaryTableToSqlStatement() + public void TemporaryTable_ComplexObjects_ShouldBePassedAsMultiColumnTemporaryTableToSqlStatement() { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entities = Generate.Multiple(); - ( - await this - .Connection.QueryAsync( - $"SELECT * FROM {TemporaryTable(entities)}", - cancellationToken: TestContext.Current.CancellationToken - ) - .ToListAsync(TestContext.Current.CancellationToken) - ) + this.Connection.Query( + $"SELECT * FROM {TemporaryTable(entities)}", + cancellationToken: TestContext.Current.CancellationToken + ) .Should() .BeEquivalentTo(entities); } [Fact] - public async Task TemporaryTableAsync_ScalarValues_Enums_EnumSerializationModeIsIntegers_ShouldSerializeEnumToInteger() + public void TemporaryTable_ScalarValues_Enums_EnumSerializationModeIsIntegers_ShouldSerializeEnumToInteger() { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -184,20 +196,16 @@ public async Task TemporaryTableAsync_ScalarValues_Enums_EnumSerializationModeIs var enumValues = Generate.Multiple(); - ( - await this - .Connection.QueryAsync( - $"SELECT {Q("Value")} FROM {TemporaryTable(enumValues)}", - cancellationToken: TestContext.Current.CancellationToken - ) - .ToListAsync(TestContext.Current.CancellationToken) - ) + this.Connection.Query( + $"SELECT {Q("Value")} FROM {TemporaryTable(enumValues)}", + cancellationToken: TestContext.Current.CancellationToken + ) .Should() .BeEquivalentTo(enumValues.Select(a => (int)a)); } [Fact] - public async Task TemporaryTableAsync_ScalarValues_Enums_EnumSerializationModeIsStrings_ShouldSerializeEnumToString() + public void TemporaryTable_ScalarValues_Enums_EnumSerializationModeIsStrings_ShouldSerializeEnumToString() { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); @@ -205,33 +213,25 @@ public async Task TemporaryTableAsync_ScalarValues_Enums_EnumSerializationModeIs var enumValues = Generate.Multiple(); - ( - await this - .Connection.QueryAsync( - $"SELECT {Q("Value")} FROM {TemporaryTable(enumValues)}", - cancellationToken: TestContext.Current.CancellationToken - ) - .ToListAsync(TestContext.Current.CancellationToken) - ) + this.Connection.Query( + $"SELECT {Q("Value")} FROM {TemporaryTable(enumValues)}", + cancellationToken: TestContext.Current.CancellationToken + ) .Should() .BeEquivalentTo(enumValues.Select(a => a.ToString())); } [Fact] - public async Task TemporaryTableAsync_ScalarValues_ShouldBePassedAsSingleColumnTemporaryTableToSqlStatement() + public void TemporaryTable_ScalarValues_ShouldBePassedAsSingleColumnTemporaryTableToSqlStatement() { Assert.SkipUnless(this.DatabaseAdapter.SupportsTemporaryTables(this.Connection), ""); var entityIds = Generate.Ids(); - ( - await this - .Connection.QueryAsync( - $"SELECT {Q("Value")} FROM {TemporaryTable(entityIds)}", - cancellationToken: TestContext.Current.CancellationToken - ) - .ToListAsync(TestContext.Current.CancellationToken) - ) + this.Connection.Query( + $"SELECT {Q("Value")} FROM {TemporaryTable(entityIds)}", + cancellationToken: TestContext.Current.CancellationToken + ) .Should() .BeEquivalentTo(entityIds); } diff --git a/tests/DbConnectionPlus.IntegrationTests/IntegrationTestsBase.cs b/tests/DbConnectionPlus.IntegrationTests/IntegrationTestsBase.cs index d58d06f..e702a19 100644 --- a/tests/DbConnectionPlus.IntegrationTests/IntegrationTestsBase.cs +++ b/tests/DbConnectionPlus.IntegrationTests/IntegrationTestsBase.cs @@ -36,6 +36,26 @@ public abstract class IntegrationTestsBase IAsyncDisposable where TTestDatabaseProvider : ITestDatabaseProvider, new() { + /// + /// The database adapter for the test database of the currently running integration test. + /// + /// + /// The adapter rather than the provider: an interface that declares a static abstract member - which + /// is - cannot be used as a type argument. + /// +#pragma warning disable S2743 + private static readonly AsyncLocal currentDatabaseAdapter = new(); +#pragma warning restore S2743 + + /// + /// The connection to the test database for the currently running integration test. + /// +#pragma warning disable S2743 + private static readonly AsyncLocal currentTestDatabaseConnection = new(); +#pragma warning restore S2743 + + private bool logDbCommands; + protected IntegrationTestsBase() { // Ensure consistent culture for tests. @@ -86,23 +106,20 @@ protected IntegrationTestsBase() /// public bool DelayNextDbCommand { get; set; } - /// - public void Dispose() - { - GC.SuppressFinalize(this); - - this.Connection.Close(); - this.Connection.Dispose(); - } + /// + /// The connection to the test database. + /// + protected DbConnection Connection { get; } - /// - public async ValueTask DisposeAsync() - { - GC.SuppressFinalize(this); + /// + /// The DbConnectionPlus database adapter for the test database. + /// + protected IDatabaseAdapter DatabaseAdapter => this.TestDatabaseProvider.DatabaseAdapter; - await this.Connection.CloseAsync(); - await this.Connection.DisposeAsync(); - } + /// + /// The provider for the test database. + /// + protected TTestDatabaseProvider TestDatabaseProvider { get; } /// /// Returns the specified parameter name with the appropriate prefix (e.g. "@" for SQL Server or ":" for Oracle) @@ -134,20 +151,36 @@ public async ValueTask DisposeAsync() public static string QT(string tableName) => currentDatabaseAdapter.Value!.QuoteTemporaryTableName(tableName, currentTestDatabaseConnection.Value!); - /// - /// The connection to the test database. - /// - protected DbConnection Connection { get; } + /// + public void Dispose() + { + GC.SuppressFinalize(this); - /// - /// The DbConnectionPlus database adapter for the test database. - /// - protected IDatabaseAdapter DatabaseAdapter => this.TestDatabaseProvider.DatabaseAdapter; + this.Connection.Close(); + this.Connection.Dispose(); + } + + /// + public async ValueTask DisposeAsync() + { + GC.SuppressFinalize(this); + + await this.Connection.CloseAsync(); + await this.Connection.DisposeAsync(); + } /// - /// The provider for the test database. + /// Creates a that will be cancelled after 100 milliseconds. /// - protected TTestDatabaseProvider TestDatabaseProvider { get; } + /// A that will be cancelled after 100 milliseconds. + protected static CancellationToken CreateCancellationTokenThatIsCancelledAfter100Milliseconds() + { +#pragma warning disable S2930 + var cancellationTokenSource = new CancellationTokenSource(); +#pragma warning restore S2930 + cancellationTokenSource.CancelAfter(100); + return cancellationTokenSource.Token; + } /// /// Creates the specified number of entities of the type and inserts them into the test @@ -353,37 +386,4 @@ private void InterceptDbCommand(DbCommand command, IReadOnlyList - /// Creates a that will be cancelled after 100 milliseconds. - /// - /// A that will be cancelled after 100 milliseconds. - protected static CancellationToken CreateCancellationTokenThatIsCancelledAfter100Milliseconds() - { -#pragma warning disable S2930 - var cancellationTokenSource = new CancellationTokenSource(); -#pragma warning restore S2930 - cancellationTokenSource.CancelAfter(100); - return cancellationTokenSource.Token; - } - - private bool logDbCommands; - - /// - /// The connection to the test database for the currently running integration test. - /// -#pragma warning disable S2743 - private static readonly AsyncLocal currentTestDatabaseConnection = new(); -#pragma warning restore S2743 - - /// - /// The database adapter for the test database of the currently running integration test. - /// - /// - /// The adapter rather than the provider: an interface that declares a static abstract member - which - /// is - cannot be used as a type argument. - /// -#pragma warning disable S2743 - private static readonly AsyncLocal currentDatabaseAdapter = new(); -#pragma warning restore S2743 } diff --git a/tests/DbConnectionPlus.IntegrationTests/Readers/CommandDisposingDataReaderDecoratorTests.cs b/tests/DbConnectionPlus.IntegrationTests/Readers/CommandDisposingDataReaderDecoratorTests.cs index b6017b8..54d04d8 100644 --- a/tests/DbConnectionPlus.IntegrationTests/Readers/CommandDisposingDataReaderDecoratorTests.cs +++ b/tests/DbConnectionPlus.IntegrationTests/Readers/CommandDisposingDataReaderDecoratorTests.cs @@ -22,7 +22,7 @@ public abstract class CommandDisposingDataReaderDecoratorTests decorator.Read()) + await Invoking(() => decorator.ReadAsync(cancellationToken)) .Should() - .Throw() + .ThrowAsync() .Where(a => a.CancellationToken == cancellationToken); } [Fact] - public async Task ReadAsync_OperationCancelledViaCancellationToken_ShouldThrowOperationCanceledException() + public void Read_OperationCancelledViaCancellationToken_ShouldThrowOperationCanceledException() { Assert.SkipUnless(this.TestDatabaseProvider.SupportsProperCommandCancellation, ""); @@ -77,7 +79,7 @@ public async Task ReadAsync_OperationCancelledViaCancellationToken_ShouldThrowOp // meaning the cancellation won't be observed until after the delay. Assert.SkipWhen(this.TestDatabaseProvider is PostgreSqlTestDatabaseProvider, ""); - await using var command = this.Connection.CreateCommand(); + using var command = this.Connection.CreateCommand(); command.CommandText = "SELECT 1; " + this.TestDatabaseProvider.DelayTwoSecondsStatement + " SELECT 1;"; using var cancellationTokenSource = new CancellationTokenSource(); @@ -93,9 +95,9 @@ public async Task ReadAsync_OperationCancelledViaCancellationToken_ShouldThrowOp var commandDisposer = new DbCommandDisposer(command, [], default); - await using var decoratedReader = await command.ExecuteReaderAsync(TestContext.Current.CancellationToken); + using var decoratedReader = command.ExecuteReader(); - await using var decorator = new CommandDisposingDataReaderDecorator( + using var decorator = new CommandDisposingDataReaderDecorator( decoratedReader, this.DatabaseAdapter, commandDisposer, @@ -103,15 +105,13 @@ public async Task ReadAsync_OperationCancelledViaCancellationToken_ShouldThrowOp ); // Read the value from before the delay: - (await decorator.ReadAsync(TestContext.Current.CancellationToken)) - .Should() - .BeTrue(); + decorator.Read().Should().BeTrue(); // The next read should be cancelled: // ReSharper disable once AccessToDisposedClosure - await Invoking(() => decorator.ReadAsync(cancellationToken)) + Invoking(() => decorator.Read()) .Should() - .ThrowAsync() + .Throw() .Where(a => a.CancellationToken == cancellationToken); } } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/MySqlContainerFixture.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/MySqlContainerFixture.cs index bcf9bbe..feb675f 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/MySqlContainerFixture.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/MySqlContainerFixture.cs @@ -15,6 +15,10 @@ internal sealed class MySqlContainerFixture() : DbContainerFixture(TestDatabaseDiagnosticMessageSink.Instance), ITestDatabaseContainerFixture { + private const string Image = "mysql:latest"; + + private const string RootUsername = "root"; + /// public override string ConnectionString => new MySqlConnectionStringBuilder @@ -39,8 +43,4 @@ protected override MySqlBuilder Configure() => new MySqlBuilder(Image) .WithUsername(RootUsername) .WithPassword(TestDatabaseContainers.Password); - - private const string Image = "mysql:latest"; - - private const string RootUsername = "root"; } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/OracleContainerFixture.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/OracleContainerFixture.cs index ac9dd4a..2f6b5ef 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/OracleContainerFixture.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/OracleContainerFixture.cs @@ -15,6 +15,20 @@ internal sealed class OracleContainerFixture() : DbContainerFixture(TestDatabaseDiagnosticMessageSink.Instance), ITestDatabaseContainerFixture { + /// + /// The image the container runs. + /// + /// + /// The faststart variants carry an already created database and come up in well under a minute, where the + /// plain image spends several minutes creating FREEPDB1 on first start. The tag has to name the major + /// version: the module reads it to decide that this image serves FREEPDB1 rather than XEPDB1. + /// + private const string Image = "gvenzl/oracle-free:23-slim-faststart"; + + private const string ServiceName = "FREEPDB1"; + + private const string SystemUsername = "SYSTEM"; + /// /// /// The tests connect as SYSTEM, not as the unprivileged application user the module creates: the @@ -32,29 +46,15 @@ internal sealed class OracleContainerFixture() /// public override DbProviderFactory DbProviderFactory => OracleClientFactory.Instance; + /// + /// The host port the container's Oracle listener is published on. + /// + private ushort MappedPort => this.Container.GetMappedPublicPort(OracleBuilder.OraclePort); + /// protected override OracleBuilder Configure() => // WithDatabase is deliberately not called: for an Oracle 18+ image the module would only pass the name // on to ORACLE_DATABASE if it differed from the pluggable database the image already ships, and asking // this one to create a second FREEPDB1 fails. new OracleBuilder(Image).WithPassword(TestDatabaseContainers.Password); - - /// - /// The host port the container's Oracle listener is published on. - /// - private ushort MappedPort => this.Container.GetMappedPublicPort(OracleBuilder.OraclePort); - - /// - /// The image the container runs. - /// - /// - /// The faststart variants carry an already created database and come up in well under a minute, where the - /// plain image spends several minutes creating FREEPDB1 on first start. The tag has to name the major - /// version: the module reads it to decide that this image serves FREEPDB1 rather than XEPDB1. - /// - private const string Image = "gvenzl/oracle-free:23-slim-faststart"; - - private const string ServiceName = "FREEPDB1"; - - private const string SystemUsername = "SYSTEM"; } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/PostgreSqlContainerFixture.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/PostgreSqlContainerFixture.cs index b954f86..4d8cdf2 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/PostgreSqlContainerFixture.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/PostgreSqlContainerFixture.cs @@ -15,6 +15,8 @@ internal sealed class PostgreSqlContainerFixture() : DbContainerFixture(TestDatabaseDiagnosticMessageSink.Instance), ITestDatabaseContainerFixture { + private const string Image = "postgres:latest"; + /// public override string ConnectionString => new NpgsqlConnectionStringBuilder @@ -31,6 +33,4 @@ internal sealed class PostgreSqlContainerFixture() /// protected override PostgreSqlBuilder Configure() => new PostgreSqlBuilder(Image).WithPassword(TestDatabaseContainers.Password); - - private const string Image = "postgres:latest"; } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/SqlServerContainerFixture.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/SqlServerContainerFixture.cs index 47f54a8..880ef2a 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/SqlServerContainerFixture.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/SqlServerContainerFixture.cs @@ -14,6 +14,8 @@ internal sealed class SqlServerContainerFixture() : DbContainerFixture(TestDatabaseDiagnosticMessageSink.Instance), ITestDatabaseContainerFixture { + private const string Image = "mcr.microsoft.com/mssql/server:2022-latest"; + /// public override string ConnectionString => new SqlConnectionStringBuilder @@ -36,6 +38,4 @@ internal sealed class SqlServerContainerFixture() /// protected override MsSqlBuilder Configure() => new MsSqlBuilder(Image).WithPassword(TestDatabaseContainers.Password); - - private const string Image = "mcr.microsoft.com/mssql/server:2022-latest"; } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainer.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainer.cs index 8011ada..9aa7126 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainer.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainer.cs @@ -19,6 +19,15 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.TestDatabase.Containe internal sealed class TestDatabaseContainer(string databaseSystemName) where TFixture : class, ITestDatabaseContainerFixture, new() { + /// + /// The started - or currently starting - fixture. + /// + /// + /// defaults to , so the + /// task - and with it the container - is created once, no matter how many test classes ask for it. + /// + private readonly Lazy> fixture = new(() => CreateAndStartAsync(databaseSystemName)); + /// /// The fixture that runs the database server. /// @@ -79,13 +88,4 @@ private static async Task CreateAndStartAsync(string databaseSystemNam return fixture; } - - /// - /// The started - or currently starting - fixture. - /// - /// - /// defaults to , so the - /// task - and with it the container - is created once, no matter how many test classes ask for it. - /// - private readonly Lazy> fixture = new(() => CreateAndStartAsync(databaseSystemName)); } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainers.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainers.cs index 50d6c05..d7657f6 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainers.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/TestDatabaseContainers.cs @@ -19,6 +19,14 @@ internal static class TestDatabaseContainers /// public const string Password = "TestTest123!"; + private static readonly TestDatabaseContainer mySql = new("MySQL"); + + private static readonly TestDatabaseContainer oracle = new("Oracle"); + + private static readonly TestDatabaseContainer postgreSql = new("PostgreSQL"); + + private static readonly TestDatabaseContainer sqlServer = new("SQL Server"); + /// /// The container running the MySQL server. /// @@ -69,12 +77,4 @@ public static async ValueTask DisposeAsync() /// Starts the SQL Server container and waits until it accepts connections. /// public static ValueTask StartSqlServerAsync() => sqlServer.StartAsync(); - - private static readonly TestDatabaseContainer mySql = new("MySQL"); - - private static readonly TestDatabaseContainer oracle = new("Oracle"); - - private static readonly TestDatabaseContainer postgreSql = new("PostgreSQL"); - - private static readonly TestDatabaseContainer sqlServer = new("SQL Server"); } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/ITestDatabaseProvider.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/ITestDatabaseProvider.cs index feef808..3562748 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/ITestDatabaseProvider.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/ITestDatabaseProvider.cs @@ -66,6 +66,17 @@ public interface ITestDatabaseProvider /// public bool TemporaryTableTextColumnInheritsCollationFromDatabase { get; } + /// + /// Starts the database server the test database runs on and waits until it accepts connections. + /// + /// + /// Called by before the first test of a test class + /// runs, so implementations must do nothing when the server is already running. For a database system that + /// runs in a Docker container this starts the container - see + /// ; SQLite runs in-process and has nothing to start. + /// + public static abstract ValueTask StartDatabaseAsync(); + /// /// Creates a connection to the test database. /// @@ -123,15 +134,4 @@ DbConnection connection /// Prepares the test database and resets it to a clean state. /// public void ResetDatabase(); - - /// - /// Starts the database server the test database runs on and waits until it accepts connections. - /// - /// - /// Called by before the first test of a test class - /// runs, so implementations must do nothing when the server is already running. For a database system that - /// runs in a Docker container this starts the container - see - /// ; SQLite runs in-process and has nothing to start. - /// - public static abstract ValueTask StartDatabaseAsync(); } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/MySqlTestDatabaseProvider.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/MySqlTestDatabaseProvider.cs index 51dace2..166cf07 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/MySqlTestDatabaseProvider.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/MySqlTestDatabaseProvider.cs @@ -11,6 +11,129 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.TestDatabase; /// public class MySqlTestDatabaseProvider : ITestDatabaseProvider { + private const string CreateDatabaseObjectsSql = """ + CREATE TABLE `Entity` + ( + `Id` BIGINT, + `BooleanValue` TINYINT(1), + `BytesValue` BLOB, + `ByteValue` TINYINT UNSIGNED, + `CharValue` CHAR(1), + `DateOnlyValue` DATE, + `DateTimeValue` DATETIME, + `DecimalValue` DECIMAL(65,30), + `DoubleValue` DOUBLE, + `EnumValue` VARCHAR(200), + `GuidValue` CHAR(36), + `Int16Value` SMALLINT, + `Int32Value` INT, + `Int64Value` BIGINT, + `NullableBooleanValue` TINYINT(1) NULL, + `SingleValue` FLOAT, + `StringValue` TEXT, + `TimeOnlyValue` TIME, + `TimeSpanValue` TIME + ); + GO + + CREATE TABLE `EntityWithEnumStoredAsString` + ( + `Id` BIGINT, + `Enum` VARCHAR(200) NULL + ); + GO + + CREATE TABLE `EntityWithEnumStoredAsInteger` + ( + `Id` BIGINT, + `Enum` INT NULL + ); + GO + + CREATE TABLE `MappingTestEntity` + ( + `Computed` INT AS (`Value`+999), + `ConcurrencyToken` BLOB, + `Identity` INT AUTO_INCREMENT PRIMARY KEY NOT NULL, + `Key1` BIGINT NOT NULL, + `Key2` BIGINT NOT NULL, + `Value` INT NOT NULL, + `NotMapped` TEXT NULL, + `RowVersion` BLOB + ); + GO + + CREATE TRIGGER Trigger_BeforeInsert_MappingTestEntity + BEFORE INSERT ON MappingTestEntity + FOR EACH ROW + BEGIN + SET NEW.RowVersion = UNHEX(REPLACE(UUID(), '-', '')); + END; + GO + + CREATE TRIGGER Trigger_BeforeUpdate_MappingTestEntity + BEFORE UPDATE ON MappingTestEntity + FOR EACH ROW + BEGIN + SET NEW.RowVersion = UNHEX(REPLACE(UUID(), '-', '')); + END; + GO + + CREATE PROCEDURE `GetEntities` () + BEGIN + SELECT * FROM `Entity`; + END; + GO + + CREATE PROCEDURE `GetEntityIds` () + BEGIN + SELECT `Id` FROM `Entity`; + END; + GO + + CREATE PROCEDURE `GetEntityIdsAndStringValues` () + BEGIN + SELECT `Id`, `StringValue` FROM `Entity`; + END; + GO + + CREATE PROCEDURE `GetFirstEntity` () + BEGIN + SELECT * FROM `Entity` LIMIT 1; + END; + GO + + CREATE PROCEDURE `GetFirstEntityId` () + BEGIN + SELECT `Id` FROM `Entity` LIMIT 1; + END; + GO + + CREATE PROCEDURE `DeleteAllEntities` () + BEGIN + DELETE FROM `Entity`; + END; + GO + """; + + private const string DatabaseName = "DbConnectionPlusTests"; + + private const string PurgeTablesSql = """ + TRUNCATE TABLE `Entity`; + GO + + TRUNCATE TABLE `EntityWithEnumStoredAsString`; + GO + + TRUNCATE TABLE `EntityWithEnumStoredAsInteger`; + GO + + TRUNCATE TABLE `MappingTestEntity`; + GO + """; + + private static bool isDatabasePrepared; + /// public bool CanRetrieveStructureOfTemporaryTables => true; @@ -44,6 +167,14 @@ public class MySqlTestDatabaseProvider : ITestDatabaseProvider /// public bool TemporaryTableTextColumnInheritsCollationFromDatabase => true; + /// + /// The connection string that connects to the MySQL server running in the test container. + /// + private static string ConnectionString => TestDatabaseContainers.MySql.ConnectionString; + + /// + public static ValueTask StartDatabaseAsync() => TestDatabaseContainers.StartMySqlAsync(); + /// public DbConnection CreateConnection() { @@ -125,14 +256,6 @@ public void ResetDatabase() ExecuteScript(connection, PurgeTablesSql); } - /// - public static ValueTask StartDatabaseAsync() => TestDatabaseContainers.StartMySqlAsync(); - - /// - /// The connection string that connects to the MySQL server running in the test container. - /// - private static string ConnectionString => TestDatabaseContainers.MySql.ConnectionString; - private static void ExecuteScript(MySqlConnection connection, string script) { var statements = script @@ -144,127 +267,4 @@ private static void ExecuteScript(MySqlConnection connection, string script) connection.ExecuteNonQuery(statement); } } - - private const string CreateDatabaseObjectsSql = """ - CREATE TABLE `Entity` - ( - `Id` BIGINT, - `BooleanValue` TINYINT(1), - `BytesValue` BLOB, - `ByteValue` TINYINT UNSIGNED, - `CharValue` CHAR(1), - `DateOnlyValue` DATE, - `DateTimeValue` DATETIME, - `DecimalValue` DECIMAL(65,30), - `DoubleValue` DOUBLE, - `EnumValue` VARCHAR(200), - `GuidValue` CHAR(36), - `Int16Value` SMALLINT, - `Int32Value` INT, - `Int64Value` BIGINT, - `NullableBooleanValue` TINYINT(1) NULL, - `SingleValue` FLOAT, - `StringValue` TEXT, - `TimeOnlyValue` TIME, - `TimeSpanValue` TIME - ); - GO - - CREATE TABLE `EntityWithEnumStoredAsString` - ( - `Id` BIGINT, - `Enum` VARCHAR(200) NULL - ); - GO - - CREATE TABLE `EntityWithEnumStoredAsInteger` - ( - `Id` BIGINT, - `Enum` INT NULL - ); - GO - - CREATE TABLE `MappingTestEntity` - ( - `Computed` INT AS (`Value`+999), - `ConcurrencyToken` BLOB, - `Identity` INT AUTO_INCREMENT PRIMARY KEY NOT NULL, - `Key1` BIGINT NOT NULL, - `Key2` BIGINT NOT NULL, - `Value` INT NOT NULL, - `NotMapped` TEXT NULL, - `RowVersion` BLOB - ); - GO - - CREATE TRIGGER Trigger_BeforeInsert_MappingTestEntity - BEFORE INSERT ON MappingTestEntity - FOR EACH ROW - BEGIN - SET NEW.RowVersion = UNHEX(REPLACE(UUID(), '-', '')); - END; - GO - - CREATE TRIGGER Trigger_BeforeUpdate_MappingTestEntity - BEFORE UPDATE ON MappingTestEntity - FOR EACH ROW - BEGIN - SET NEW.RowVersion = UNHEX(REPLACE(UUID(), '-', '')); - END; - GO - - CREATE PROCEDURE `GetEntities` () - BEGIN - SELECT * FROM `Entity`; - END; - GO - - CREATE PROCEDURE `GetEntityIds` () - BEGIN - SELECT `Id` FROM `Entity`; - END; - GO - - CREATE PROCEDURE `GetEntityIdsAndStringValues` () - BEGIN - SELECT `Id`, `StringValue` FROM `Entity`; - END; - GO - - CREATE PROCEDURE `GetFirstEntity` () - BEGIN - SELECT * FROM `Entity` LIMIT 1; - END; - GO - - CREATE PROCEDURE `GetFirstEntityId` () - BEGIN - SELECT `Id` FROM `Entity` LIMIT 1; - END; - GO - - CREATE PROCEDURE `DeleteAllEntities` () - BEGIN - DELETE FROM `Entity`; - END; - GO - """; - - private const string DatabaseName = "DbConnectionPlusTests"; - - private const string PurgeTablesSql = """ - TRUNCATE TABLE `Entity`; - GO - - TRUNCATE TABLE `EntityWithEnumStoredAsString`; - GO - - TRUNCATE TABLE `EntityWithEnumStoredAsInteger`; - GO - - TRUNCATE TABLE `MappingTestEntity`; - GO - """; - - private static bool isDatabasePrepared; } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/OracleTestDatabaseProvider.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/OracleTestDatabaseProvider.cs index f43ff6d..e9abf61 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/OracleTestDatabaseProvider.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/OracleTestDatabaseProvider.cs @@ -11,117 +11,6 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.TestDatabase; /// public class OracleTestDatabaseProvider : ITestDatabaseProvider { - /// - public bool CanRetrieveStructureOfTemporaryTables => false; - - /// - public IDatabaseAdapter DatabaseAdapter => new OracleDatabaseAdapter(); - - /// - public string DatabaseCollation => throw new NotImplementedException(); - - /// - public string DelayTwoSecondsStatement => "BEGIN DBMS_LOCK.SLEEP(2); END;"; - - /// - public bool HasUnsupportedDataType => false; - - /// - public bool SupportsCommandExecutionWhileDataReaderIsOpen => true; - - /// - public bool SupportsDateTimeOffset => true; - - /// - public bool SupportsProperCommandCancellation => false; - - /// - public bool SupportsStoredProcedures => true; - - /// - public bool SupportsStoredProceduresReturningResultSet => false; - - /// - public bool TemporaryTableTextColumnInheritsCollationFromDatabase => true; - - /// - public DbConnection CreateConnection() - { - var connection = new OracleConnection(ConnectionString); - - // Clear the connection we got from the pool, so that its session actually ends. - // Otherwise, Oracle will keep temporary tables alive for that session and we will eventually run out of them. - OracleConnection.ClearPool(connection); - - connection.Open(); - return connection; - } - - /// - public bool ExistsTemporaryTable(string tableName, DbConnection connection, DbTransaction? transaction = null) - { - var quoteTemporaryTableName = this.DatabaseAdapter.QuoteTemporaryTableName(tableName, connection); - var unquotedTemporaryTableName = quoteTemporaryTableName[1..^1]; // Strip the quotes ("). - - return connection.Exists( - $"SELECT * FROM USER_PRIVATE_TEMP_TABLES WHERE TABLE_NAME = {Parameter(unquotedTemporaryTableName)}" - ); - } - - /// - public string GetCollationOfTemporaryTableColumn( - string temporaryTableName, - string columnName, - DbConnection connection - ) => throw new NotImplementedException(); - - /// - public string GetDataTypeOfTemporaryTableColumn( - string temporaryTableName, - string columnName, - DbConnection connection - ) => throw new NotImplementedException(); - - /// - public string GetUnsupportedDataTypeLiteral() => throw new NotImplementedException(); - - /// - public void ResetDatabase() - { - using var connection = new OracleConnection(ConnectionString); - connection.Open(); - - if (!isDatabasePrepared) - { - ExecuteScript(connection, DropDatabaseObjectsSql); - ExecuteScript(connection, CreateDatabaseObjectsSql); - - isDatabasePrepared = true; - } - - ExecuteScript(connection, PurgeTablesSql); - } - - /// - public static ValueTask StartDatabaseAsync() => TestDatabaseContainers.StartOracleAsync(); - - /// - /// The connection string that connects to the Oracle server running in the test container. - /// - private static string ConnectionString => TestDatabaseContainers.Oracle.ConnectionString; - - private static void ExecuteScript(OracleConnection connection, string script) - { - var statements = script - .Split("GO", StringSplitOptions.RemoveEmptyEntries) - .Where(a => !string.IsNullOrWhiteSpace(a.Trim())); - - foreach (var statement in statements) - { - connection.ExecuteNonQuery(statement); - } - } - private const string CreateDatabaseObjectsSql = """ CREATE TABLE "Entity" ( @@ -236,4 +125,115 @@ CREATE OR REPLACE NONEDITIONABLE PROCEDURE "DeleteAllEntities" AS """; private static bool isDatabasePrepared; + + /// + public bool CanRetrieveStructureOfTemporaryTables => false; + + /// + public IDatabaseAdapter DatabaseAdapter => new OracleDatabaseAdapter(); + + /// + public string DatabaseCollation => throw new NotImplementedException(); + + /// + public string DelayTwoSecondsStatement => "BEGIN DBMS_LOCK.SLEEP(2); END;"; + + /// + public bool HasUnsupportedDataType => false; + + /// + public bool SupportsCommandExecutionWhileDataReaderIsOpen => true; + + /// + public bool SupportsDateTimeOffset => true; + + /// + public bool SupportsProperCommandCancellation => false; + + /// + public bool SupportsStoredProcedures => true; + + /// + public bool SupportsStoredProceduresReturningResultSet => false; + + /// + public bool TemporaryTableTextColumnInheritsCollationFromDatabase => true; + + /// + /// The connection string that connects to the Oracle server running in the test container. + /// + private static string ConnectionString => TestDatabaseContainers.Oracle.ConnectionString; + + /// + public static ValueTask StartDatabaseAsync() => TestDatabaseContainers.StartOracleAsync(); + + /// + public DbConnection CreateConnection() + { + var connection = new OracleConnection(ConnectionString); + + // Clear the connection we got from the pool, so that its session actually ends. + // Otherwise, Oracle will keep temporary tables alive for that session and we will eventually run out of them. + OracleConnection.ClearPool(connection); + + connection.Open(); + return connection; + } + + /// + public bool ExistsTemporaryTable(string tableName, DbConnection connection, DbTransaction? transaction = null) + { + var quoteTemporaryTableName = this.DatabaseAdapter.QuoteTemporaryTableName(tableName, connection); + var unquotedTemporaryTableName = quoteTemporaryTableName[1..^1]; // Strip the quotes ("). + + return connection.Exists( + $"SELECT * FROM USER_PRIVATE_TEMP_TABLES WHERE TABLE_NAME = {Parameter(unquotedTemporaryTableName)}" + ); + } + + /// + public string GetCollationOfTemporaryTableColumn( + string temporaryTableName, + string columnName, + DbConnection connection + ) => throw new NotImplementedException(); + + /// + public string GetDataTypeOfTemporaryTableColumn( + string temporaryTableName, + string columnName, + DbConnection connection + ) => throw new NotImplementedException(); + + /// + public string GetUnsupportedDataTypeLiteral() => throw new NotImplementedException(); + + /// + public void ResetDatabase() + { + using var connection = new OracleConnection(ConnectionString); + connection.Open(); + + if (!isDatabasePrepared) + { + ExecuteScript(connection, DropDatabaseObjectsSql); + ExecuteScript(connection, CreateDatabaseObjectsSql); + + isDatabasePrepared = true; + } + + ExecuteScript(connection, PurgeTablesSql); + } + + private static void ExecuteScript(OracleConnection connection, string script) + { + var statements = script + .Split("GO", StringSplitOptions.RemoveEmptyEntries) + .Where(a => !string.IsNullOrWhiteSpace(a.Trim())); + + foreach (var statement in statements) + { + connection.ExecuteNonQuery(statement); + } + } } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/PostgreSqlTestDatabaseProvider.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/PostgreSqlTestDatabaseProvider.cs index 7a082b8..672930f 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/PostgreSqlTestDatabaseProvider.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/PostgreSqlTestDatabaseProvider.cs @@ -11,117 +11,6 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.TestDatabase; /// public class PostgreSqlTestDatabaseProvider : ITestDatabaseProvider { - /// - public bool CanRetrieveStructureOfTemporaryTables => true; - - /// - public IDatabaseAdapter DatabaseAdapter => new PostgreSqlDatabaseAdapter(); - - /// - public string DatabaseCollation => throw new NotImplementedException(); - - /// - public string DelayTwoSecondsStatement => "SELECT pg_sleep(2);"; - - /// - public bool HasUnsupportedDataType => true; - - /// - public bool SupportsCommandExecutionWhileDataReaderIsOpen => false; - - /// - public bool SupportsDateTimeOffset => false; - - /// - public bool SupportsProperCommandCancellation => true; - - /// - public bool SupportsStoredProcedures => true; - - /// - public bool SupportsStoredProceduresReturningResultSet => false; - - /// - public bool TemporaryTableTextColumnInheritsCollationFromDatabase => true; - - /// - public DbConnection CreateConnection() - { - var connection = new NpgsqlConnection(ConnectionString); - connection.Open(); - connection.ChangeDatabase(DatabaseName); - return connection; - } - - /// - public bool ExistsTemporaryTable(string tableName, DbConnection connection, DbTransaction? transaction = null) => - connection.Exists( - $""" - SELECT 1 - FROM information_schema.tables - WHERE table_type = 'LOCAL TEMPORARY' AND - table_name = '{tableName}' - """, - transaction, - cancellationToken: TestContext.Current.CancellationToken - ); - - /// - public string GetCollationOfTemporaryTableColumn( - string temporaryTableName, - string columnName, - DbConnection connection - ) => throw new NotImplementedException(); - - /// - public string GetDataTypeOfTemporaryTableColumn( - string temporaryTableName, - string columnName, - DbConnection connection - ) => - connection.QuerySingle( - $""" - SELECT data_type - FROM information_schema.columns - WHERE table_schema LIKE 'pg_temp%' AND - table_name = '{temporaryTableName}' AND - column_name = '{columnName}' - """, - cancellationToken: TestContext.Current.CancellationToken - ); - - /// - public string GetUnsupportedDataTypeLiteral() => "(1, 2)"; - - public void ResetDatabase() - { - using var connection = new NpgsqlConnection(ConnectionString); - connection.Open(); - - if (!isDatabasePrepared) - { - connection.ExecuteNonQuery($"DROP DATABASE IF EXISTS \"{DatabaseName}\" WITH (FORCE)"); - connection.ExecuteNonQuery($"CREATE DATABASE \"{DatabaseName}\""); - - connection.ChangeDatabase(DatabaseName); - - connection.ExecuteNonQuery(CreateDatabaseObjectsSql); - - isDatabasePrepared = true; - } - - connection.ChangeDatabase(DatabaseName); - connection.ExecuteNonQuery(PurgeTablesSql); - } - - /// - public static ValueTask StartDatabaseAsync() => TestDatabaseContainers.StartPostgreSqlAsync(); - - /// - /// The connection string that connects to the PostgreSQL server running in the test container. - /// - private static string ConnectionString => TestDatabaseContainers.PostgreSql.ConnectionString; - private const string CreateDatabaseObjectsSql = """ CREATE EXTENSION IF NOT EXISTS pgcrypto; -- Needed for gen_random_bytes() @@ -233,4 +122,115 @@ DELETE FROM "Entity" """; private static bool isDatabasePrepared; + + /// + public bool CanRetrieveStructureOfTemporaryTables => true; + + /// + public IDatabaseAdapter DatabaseAdapter => new PostgreSqlDatabaseAdapter(); + + /// + public string DatabaseCollation => throw new NotImplementedException(); + + /// + public string DelayTwoSecondsStatement => "SELECT pg_sleep(2);"; + + /// + public bool HasUnsupportedDataType => true; + + /// + public bool SupportsCommandExecutionWhileDataReaderIsOpen => false; + + /// + public bool SupportsDateTimeOffset => false; + + /// + public bool SupportsProperCommandCancellation => true; + + /// + public bool SupportsStoredProcedures => true; + + /// + public bool SupportsStoredProceduresReturningResultSet => false; + + /// + public bool TemporaryTableTextColumnInheritsCollationFromDatabase => true; + + /// + /// The connection string that connects to the PostgreSQL server running in the test container. + /// + private static string ConnectionString => TestDatabaseContainers.PostgreSql.ConnectionString; + + /// + public static ValueTask StartDatabaseAsync() => TestDatabaseContainers.StartPostgreSqlAsync(); + + /// + public DbConnection CreateConnection() + { + var connection = new NpgsqlConnection(ConnectionString); + connection.Open(); + connection.ChangeDatabase(DatabaseName); + return connection; + } + + /// + public bool ExistsTemporaryTable(string tableName, DbConnection connection, DbTransaction? transaction = null) => + connection.Exists( + $""" + SELECT 1 + FROM information_schema.tables + WHERE table_type = 'LOCAL TEMPORARY' AND + table_name = '{tableName}' + """, + transaction, + cancellationToken: TestContext.Current.CancellationToken + ); + + /// + public string GetCollationOfTemporaryTableColumn( + string temporaryTableName, + string columnName, + DbConnection connection + ) => throw new NotImplementedException(); + + /// + public string GetDataTypeOfTemporaryTableColumn( + string temporaryTableName, + string columnName, + DbConnection connection + ) => + connection.QuerySingle( + $""" + SELECT data_type + FROM information_schema.columns + WHERE table_schema LIKE 'pg_temp%' AND + table_name = '{temporaryTableName}' AND + column_name = '{columnName}' + """, + cancellationToken: TestContext.Current.CancellationToken + ); + + /// + public string GetUnsupportedDataTypeLiteral() => "(1, 2)"; + + public void ResetDatabase() + { + using var connection = new NpgsqlConnection(ConnectionString); + connection.Open(); + + if (!isDatabasePrepared) + { + connection.ExecuteNonQuery($"DROP DATABASE IF EXISTS \"{DatabaseName}\" WITH (FORCE)"); + connection.ExecuteNonQuery($"CREATE DATABASE \"{DatabaseName}\""); + + connection.ChangeDatabase(DatabaseName); + + connection.ExecuteNonQuery(CreateDatabaseObjectsSql); + + isDatabasePrepared = true; + } + + connection.ChangeDatabase(DatabaseName); + connection.ExecuteNonQuery(PurgeTablesSql); + } } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SQLiteTestDatabaseProvider.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SQLiteTestDatabaseProvider.cs index 7b70210..af136bc 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SQLiteTestDatabaseProvider.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SQLiteTestDatabaseProvider.cs @@ -12,6 +12,72 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.TestDatabase; /// public class SqliteTestDatabaseProvider : ITestDatabaseProvider { + private const string CreateDatabaseObjectsSql = """ + CREATE TABLE Entity + ( + Id INTEGER, + BooleanValue INTEGER, + BytesValue BLOB, + ByteValue INTEGER, + CharValue TEXT, + DateOnlyValue TEXT, + DateTimeValue TEXT, + DecimalValue TEXT, + DoubleValue REAL, + EnumValue TEXT, + GuidValue TEXT, + Int16Value INTEGER, + Int32Value INTEGER, + Int64Value INTEGER, + NullableBooleanValue INTEGER NULL, + SingleValue REAL, + StringValue TEXT, + TimeOnlyValue TEXT, + TimeSpanValue TEXT + ); + + CREATE TABLE EntityWithDateTimeOffset + ( + Id INTEGER, + DateTimeOffsetValue TEXT + ); + + CREATE TABLE EntityWithEnumStoredAsString + ( + Id INTEGER, + Enum TEXT + ); + + CREATE TABLE EntityWithEnumStoredAsInteger + ( + Id INTEGER, + Enum INTEGER + ); + + CREATE TABLE MappingTestEntity + ( + Computed INTEGER GENERATED ALWAYS AS (Value+999) VIRTUAL, + ConcurrencyToken BLOB, + Identity INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + Key1 INTEGER NOT NULL, + Key2 INTEGER NOT NULL, + Value INTEGER NOT NULL, + RowVersion BLOB DEFAULT (randomblob(8)), + NotMapped TEXT NULL + ); + + CREATE TRIGGER TriggerMappingTestEntity + BEFORE UPDATE ON MappingTestEntity + FOR EACH ROW + BEGIN + UPDATE MappingTestEntity SET RowVersion = randomblob(8) WHERE Key1 = OLD.Key1 AND Key2 = OLD.Key2; + END; + """; + + private readonly SqliteConnection connection; + + private bool isDatabasePrepared; + /// /// Initializes a new instance of the class. /// @@ -62,6 +128,10 @@ SELECT x + 1 FROM delay WHERE x < 5000000 /// public bool TemporaryTableTextColumnInheritsCollationFromDatabase => true; + /// + /// SQLite runs in-process, in memory, so there is no server and nothing to start. + public static ValueTask StartDatabaseAsync() => default; + /// public DbConnection CreateConnection() => this.connection; @@ -115,74 +185,4 @@ public void ResetDatabase() this.isDatabasePrepared = true; } } - - /// - /// SQLite runs in-process, in memory, so there is no server and nothing to start. - public static ValueTask StartDatabaseAsync() => default; - - private readonly SqliteConnection connection; - - private bool isDatabasePrepared; - - private const string CreateDatabaseObjectsSql = """ - CREATE TABLE Entity - ( - Id INTEGER, - BooleanValue INTEGER, - BytesValue BLOB, - ByteValue INTEGER, - CharValue TEXT, - DateOnlyValue TEXT, - DateTimeValue TEXT, - DecimalValue TEXT, - DoubleValue REAL, - EnumValue TEXT, - GuidValue TEXT, - Int16Value INTEGER, - Int32Value INTEGER, - Int64Value INTEGER, - NullableBooleanValue INTEGER NULL, - SingleValue REAL, - StringValue TEXT, - TimeOnlyValue TEXT, - TimeSpanValue TEXT - ); - - CREATE TABLE EntityWithDateTimeOffset - ( - Id INTEGER, - DateTimeOffsetValue TEXT - ); - - CREATE TABLE EntityWithEnumStoredAsString - ( - Id INTEGER, - Enum TEXT - ); - - CREATE TABLE EntityWithEnumStoredAsInteger - ( - Id INTEGER, - Enum INTEGER - ); - - CREATE TABLE MappingTestEntity - ( - Computed INTEGER GENERATED ALWAYS AS (Value+999) VIRTUAL, - ConcurrencyToken BLOB, - Identity INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - Key1 INTEGER NOT NULL, - Key2 INTEGER NOT NULL, - Value INTEGER NOT NULL, - RowVersion BLOB DEFAULT (randomblob(8)), - NotMapped TEXT NULL - ); - - CREATE TRIGGER TriggerMappingTestEntity - BEFORE UPDATE ON MappingTestEntity - FOR EACH ROW - BEGIN - UPDATE MappingTestEntity SET RowVersion = randomblob(8) WHERE Key1 = OLD.Key1 AND Key2 = OLD.Key2; - END; - """; } diff --git a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SqlServerTestDatabaseProvider.cs b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SqlServerTestDatabaseProvider.cs index 4e8b21c..f2ace9c 100644 --- a/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SqlServerTestDatabaseProvider.cs +++ b/tests/DbConnectionPlus.IntegrationTests/TestDatabase/SqlServerTestDatabaseProvider.cs @@ -10,6 +10,130 @@ namespace RentADeveloper.DbConnectionPlus.IntegrationTests.TestDatabase; /// public class SqlServerTestDatabaseProvider : ITestDatabaseProvider { + private const string CreateDatabaseObjectsSql = """ + CREATE TABLE Entity + ( + Id BIGINT NOT NULL PRIMARY KEY, + BooleanValue BIT, + BytesValue VARBINARY(MAX), + ByteValue TINYINT, + CharValue CHAR(1), + DateOnlyValue DATE, + DateTimeValue DATETIME2, + DecimalValue DECIMAL(28,10), + DoubleValue FLOAT, + EnumValue NVARCHAR(200), + GuidValue UNIQUEIDENTIFIER, + Int16Value SMALLINT, + Int32Value INT, + Int64Value BIGINT, + NullableBooleanValue BIT NULL, + SingleValue REAL, + StringValue NVARCHAR(MAX), + TimeOnlyValue TIME, + TimeSpanValue TIME + ); + GO + + CREATE TABLE EntityWithDateTimeOffset + ( + Id BIGINT NOT NULL PRIMARY KEY, + DateTimeOffsetValue DATETIMEOFFSET NULL + ); + GO + + CREATE TABLE EntityWithEnumStoredAsString + ( + Id BIGINT NOT NULL PRIMARY KEY, + Enum NVARCHAR(200) NULL + ); + GO + + CREATE TABLE EntityWithEnumStoredAsInteger + ( + Id BIGINT NOT NULL PRIMARY KEY, + Enum INT NULL + ); + GO + + CREATE TABLE MappingTestEntity + ( + Computed AS ([Value]+(999)), + ConcurrencyToken VARBINARY(max), + [Identity] INT IDENTITY(1,1) NOT NULL, + Key1 BIGINT NOT NULL, + Key2 BIGINT NOT NULL, + Value INT NOT NULL, + NotMapped VARCHAR(200) NULL, + RowVersion ROWVERSION, + PRIMARY KEY (Key1, Key2) + ); + GO + + CREATE PROCEDURE GetEntities + AS + BEGIN + SELECT * FROM Entity + END; + GO + + CREATE PROCEDURE GetEntityIds + AS + BEGIN + SELECT Id FROM Entity + END; + GO + + CREATE PROCEDURE GetEntityIdsAndStringValues + AS + BEGIN + SELECT Id, StringValue FROM Entity + END; + GO + + CREATE PROCEDURE GetFirstEntity + AS + BEGIN + SELECT TOP 1 * FROM Entity + END; + GO + + CREATE PROCEDURE GetFirstEntityId + AS + BEGIN + SELECT TOP 1 Id FROM Entity + END; + GO + + CREATE PROCEDURE DeleteAllEntities + AS + BEGIN + DELETE FROM Entity + END; + GO + """; + + private const string DatabaseName = "DbConnectionPlusTests"; + + private const string PurgeTablesSql = """ + TRUNCATE TABLE Entity; + GO + + TRUNCATE TABLE EntityWithDateTimeOffset; + GO + + TRUNCATE TABLE EntityWithEnumStoredAsString; + GO + + TRUNCATE TABLE EntityWithEnumStoredAsInteger; + GO + + TRUNCATE TABLE MappingTestEntity; + GO + """; + + private static bool isDatabasePrepared; + /// public bool CanRetrieveStructureOfTemporaryTables => true; @@ -43,6 +167,14 @@ public class SqlServerTestDatabaseProvider : ITestDatabaseProvider /// public bool TemporaryTableTextColumnInheritsCollationFromDatabase => false; + /// + /// The connection string that connects to the SQL Server server running in the test container. + /// + private static string ConnectionString => TestDatabaseContainers.SqlServer.ConnectionString; + + /// + public static ValueTask StartDatabaseAsync() => TestDatabaseContainers.StartSqlServerAsync(); + /// public DbConnection CreateConnection() { @@ -128,14 +260,6 @@ IF EXISTS (SELECT name FROM sys.databases WHERE name = N'{DatabaseName}') ExecuteScript(connection, PurgeTablesSql); } - /// - public static ValueTask StartDatabaseAsync() => TestDatabaseContainers.StartSqlServerAsync(); - - /// - /// The connection string that connects to the SQL Server server running in the test container. - /// - private static string ConnectionString => TestDatabaseContainers.SqlServer.ConnectionString; - private static void ExecuteScript(SqlConnection connection, string script) { var statements = script @@ -147,128 +271,4 @@ private static void ExecuteScript(SqlConnection connection, string script) connection.ExecuteNonQuery(statement); } } - - private const string CreateDatabaseObjectsSql = """ - CREATE TABLE Entity - ( - Id BIGINT NOT NULL PRIMARY KEY, - BooleanValue BIT, - BytesValue VARBINARY(MAX), - ByteValue TINYINT, - CharValue CHAR(1), - DateOnlyValue DATE, - DateTimeValue DATETIME2, - DecimalValue DECIMAL(28,10), - DoubleValue FLOAT, - EnumValue NVARCHAR(200), - GuidValue UNIQUEIDENTIFIER, - Int16Value SMALLINT, - Int32Value INT, - Int64Value BIGINT, - NullableBooleanValue BIT NULL, - SingleValue REAL, - StringValue NVARCHAR(MAX), - TimeOnlyValue TIME, - TimeSpanValue TIME - ); - GO - - CREATE TABLE EntityWithDateTimeOffset - ( - Id BIGINT NOT NULL PRIMARY KEY, - DateTimeOffsetValue DATETIMEOFFSET NULL - ); - GO - - CREATE TABLE EntityWithEnumStoredAsString - ( - Id BIGINT NOT NULL PRIMARY KEY, - Enum NVARCHAR(200) NULL - ); - GO - - CREATE TABLE EntityWithEnumStoredAsInteger - ( - Id BIGINT NOT NULL PRIMARY KEY, - Enum INT NULL - ); - GO - - CREATE TABLE MappingTestEntity - ( - Computed AS ([Value]+(999)), - ConcurrencyToken VARBINARY(max), - [Identity] INT IDENTITY(1,1) NOT NULL, - Key1 BIGINT NOT NULL, - Key2 BIGINT NOT NULL, - Value INT NOT NULL, - NotMapped VARCHAR(200) NULL, - RowVersion ROWVERSION, - PRIMARY KEY (Key1, Key2) - ); - GO - - CREATE PROCEDURE GetEntities - AS - BEGIN - SELECT * FROM Entity - END; - GO - - CREATE PROCEDURE GetEntityIds - AS - BEGIN - SELECT Id FROM Entity - END; - GO - - CREATE PROCEDURE GetEntityIdsAndStringValues - AS - BEGIN - SELECT Id, StringValue FROM Entity - END; - GO - - CREATE PROCEDURE GetFirstEntity - AS - BEGIN - SELECT TOP 1 * FROM Entity - END; - GO - - CREATE PROCEDURE GetFirstEntityId - AS - BEGIN - SELECT TOP 1 Id FROM Entity - END; - GO - - CREATE PROCEDURE DeleteAllEntities - AS - BEGIN - DELETE FROM Entity - END; - GO - """; - - private const string DatabaseName = "DbConnectionPlusTests"; - - private const string PurgeTablesSql = """ - TRUNCATE TABLE Entity; - GO - - TRUNCATE TABLE EntityWithDateTimeOffset; - GO - - TRUNCATE TABLE EntityWithEnumStoredAsString; - GO - - TRUNCATE TABLE EntityWithEnumStoredAsInteger; - GO - - TRUNCATE TABLE MappingTestEntity; - GO - """; - - private static bool isDatabasePrepared; } diff --git a/tests/DbConnectionPlus.UnitTests/Assertions/DecoratorAssertions.cs b/tests/DbConnectionPlus.UnitTests/Assertions/DecoratorAssertions.cs index 311884d..c916e93 100644 --- a/tests/DbConnectionPlus.UnitTests/Assertions/DecoratorAssertions.cs +++ b/tests/DbConnectionPlus.UnitTests/Assertions/DecoratorAssertions.cs @@ -11,6 +11,15 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.Assertions; /// public static class DecoratorAssertions { + /// + /// The method. + /// + private static readonly MethodInfo specimenFactoryCreateMethod = typeof(SpecimenFactory).GetMethod( + nameof(SpecimenFactory.Create), + BindingFlags.Public | BindingFlags.Static, + [typeof(ISpecimenBuilder)] + )!; + /// /// /// Asserts that forwards all calls to , meaning each @@ -107,13 +116,4 @@ HashSet excludedMethods } } } - - /// - /// The method. - /// - private static readonly MethodInfo specimenFactoryCreateMethod = typeof(SpecimenFactory).GetMethod( - nameof(SpecimenFactory.Create), - BindingFlags.Public | BindingFlags.Static, - [typeof(ISpecimenBuilder)] - )!; } diff --git a/tests/DbConnectionPlus.UnitTests/Configuration/EntityTypeBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/Configuration/EntityTypeBuilderTests.cs index 2049a98..bc7f492 100644 --- a/tests/DbConnectionPlus.UnitTests/Configuration/EntityTypeBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Configuration/EntityTypeBuilderTests.cs @@ -29,6 +29,28 @@ public void Freeze_ShouldFreezeBuilderAndAllPropertyBuilders() .WithMessage("The configuration of DbConnectionPlus is frozen and can no longer be modified."); } + [Fact] + public void PropertyBuilders_ShouldGetBuildersOfConfiguredProperties() + { + var builder = new EntityTypeBuilder(); + + builder.Property(a => a.Id).IsKey(); + builder.Property(a => a.StringValue).IsComputed(); + builder.Property(a => a.Int64Value).IsIgnored(); + + var propertyBuilders = ((IEntityTypeBuilder)builder).PropertyBuilders; + + propertyBuilders.Should().HaveCount(3); + + propertyBuilders.Should().ContainKeys("Id", "StringValue", "Int64Value"); + + propertyBuilders["Id"].Should().BeSameAs(builder.Property(a => a.Id)); + + propertyBuilders["StringValue"].Should().BeSameAs(builder.Property(a => a.StringValue)); + + propertyBuilders["Int64Value"].Should().BeSameAs(builder.Property(a => a.Int64Value)); + } + [Fact] public void Property_InvalidExpression_ShouldThrow() { @@ -55,28 +77,6 @@ public void Property_ShouldGetPropertyBuilder() builder.Property(a => a.Id).Should().BeSameAs(propertyBuilder); } - [Fact] - public void PropertyBuilders_ShouldGetBuildersOfConfiguredProperties() - { - var builder = new EntityTypeBuilder(); - - builder.Property(a => a.Id).IsKey(); - builder.Property(a => a.StringValue).IsComputed(); - builder.Property(a => a.Int64Value).IsIgnored(); - - var propertyBuilders = ((IEntityTypeBuilder)builder).PropertyBuilders; - - propertyBuilders.Should().HaveCount(3); - - propertyBuilders.Should().ContainKeys("Id", "StringValue", "Int64Value"); - - propertyBuilders["Id"].Should().BeSameAs(builder.Property(a => a.Id)); - - propertyBuilders["StringValue"].Should().BeSameAs(builder.Property(a => a.StringValue)); - - propertyBuilders["Int64Value"].Should().BeSameAs(builder.Property(a => a.Int64Value)); - } - [Fact] public void ShouldGuardAgainstNullArguments() { diff --git a/tests/DbConnectionPlus.UnitTests/Converters/EnumConverterTests.cs b/tests/DbConnectionPlus.UnitTests/Converters/EnumConverterTests.cs index e9e8171..f7eec34 100644 --- a/tests/DbConnectionPlus.UnitTests/Converters/EnumConverterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Converters/EnumConverterTests.cs @@ -4,9 +4,68 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.Converters; public class EnumConverterTests : UnitTestsBase { + public static IEnumerable<(object value, TestEnum expectedResult)> GetConvertValueToEnumMemberTestData() => + [ + ((short)1, TestEnum.Value1), + ((short)2, TestEnum.Value2), + ((short)3, TestEnum.Value3), + ((short)4, TestEnum.Value4), + ((short)5, TestEnum.Value5), + (1, TestEnum.Value1), + (2, TestEnum.Value2), + (3, TestEnum.Value3), + (4, TestEnum.Value4), + (5, TestEnum.Value5), + (1L, TestEnum.Value1), + (2L, TestEnum.Value2), + (3L, TestEnum.Value3), + (4L, TestEnum.Value4), + (5L, TestEnum.Value5), + ((byte)1, TestEnum.Value1), + ((byte)2, TestEnum.Value2), + ((byte)3, TestEnum.Value3), + ((byte)4, TestEnum.Value4), + ((byte)5, TestEnum.Value5), + ((float)1.0, TestEnum.Value1), + ((float)2.0, TestEnum.Value2), + ((float)3.0, TestEnum.Value3), + ((float)4.0, TestEnum.Value4), + ((float)5.0, TestEnum.Value5), + (1.0, TestEnum.Value1), + (2.0, TestEnum.Value2), + (3.0, TestEnum.Value3), + (4.0, TestEnum.Value4), + (5.0, TestEnum.Value5), + ((decimal)1.0, TestEnum.Value1), + ((decimal)2.0, TestEnum.Value2), + ((decimal)3.0, TestEnum.Value3), + ((decimal)4.0, TestEnum.Value4), + ((decimal)5.0, TestEnum.Value5), + ("Value1", TestEnum.Value1), + ("Value2", TestEnum.Value2), + ("Value3", TestEnum.Value3), + ("Value4", TestEnum.Value4), + ("Value5", TestEnum.Value5), + ("VALUE1", TestEnum.Value1), + ("VALUE2", TestEnum.Value2), + ("VALUE3", TestEnum.Value3), + ("VALUE4", TestEnum.Value4), + ("VALUE5", TestEnum.Value5), + ("1", TestEnum.Value1), + ("2", TestEnum.Value2), + ("3", TestEnum.Value3), + ("4", TestEnum.Value4), + ("5", TestEnum.Value5), + (TestEnum.Value1, TestEnum.Value1), + (TestEnum.Value2, TestEnum.Value2), + (TestEnum.Value3, TestEnum.Value3), + (TestEnum.Value4, TestEnum.Value4), + (TestEnum.Value5, TestEnum.Value5), + ]; + [Fact] - public void ConvertValueToEnumMember_EmptyStringValue_ShouldThrow() => - Invoking(() => EnumConverter.ConvertValueToEnumMember(string.Empty, typeof(TestEnum))) + public void ConvertValueToEnumMemberOfT_EmptyStringValue_ShouldThrow() => + Invoking(() => EnumConverter.ConvertValueToEnumMember(string.Empty)) .Should() .Throw() .WithMessage( @@ -15,9 +74,9 @@ public void ConvertValueToEnumMember_EmptyStringValue_ShouldThrow() => ); [Fact] - public void ConvertValueToEnumMember_NonEnumTargetType_ShouldThrow() + public void ConvertValueToEnumMemberOfT_NonEnumTargetType_ShouldThrow() { - Invoking(() => EnumConverter.ConvertValueToEnumMember("ValueA", typeof(int))) + Invoking(() => EnumConverter.ConvertValueToEnumMember("ValueA")) .Should() .Throw() .WithMessage( @@ -25,7 +84,7 @@ public void ConvertValueToEnumMember_NonEnumTargetType_ShouldThrow() + $"{typeof(int)}, because the type {typeof(int)} is not an enum type.*" ); - Invoking(() => EnumConverter.ConvertValueToEnumMember("ValueA", typeof(int?))) + Invoking(() => EnumConverter.ConvertValueToEnumMember("ValueA")) .Should() .Throw() .WithMessage( @@ -35,30 +94,30 @@ public void ConvertValueToEnumMember_NonEnumTargetType_ShouldThrow() } [Fact] - public void ConvertValueToEnumMember_NonNullableTargetType_NullOrDBNullValue_ShouldThrow() + public void ConvertValueToEnumMemberOfT_NonNullableTargetType_NullOrDBNullValue_ShouldThrow() { - Invoking(() => EnumConverter.ConvertValueToEnumMember(DBNull.Value, typeof(TestEnum))) + Invoking(() => EnumConverter.ConvertValueToEnumMember(DBNull.Value)) .Should() .Throw() .WithMessage($"Could not convert {{null}} to an enum member of the type {typeof(TestEnum)}."); - Invoking(() => EnumConverter.ConvertValueToEnumMember(null, typeof(TestEnum))) + Invoking(() => EnumConverter.ConvertValueToEnumMember(null)) .Should() .Throw() .WithMessage($"Could not convert {{null}} to an enum member of the type {typeof(TestEnum)}."); } [Fact] - public void ConvertValueToEnumMember_NullableTargetType_NullOrDBNullValue_ShouldReturnNull() + public void ConvertValueToEnumMemberOfT_NullableTargetType_NullOrDBNullValue_ShouldReturnNull() { - EnumConverter.ConvertValueToEnumMember(DBNull.Value, typeof(TestEnum?)).Should().BeNull(); + EnumConverter.ConvertValueToEnumMember(DBNull.Value).Should().BeNull(); - EnumConverter.ConvertValueToEnumMember(null, typeof(TestEnum?)).Should().BeNull(); + EnumConverter.ConvertValueToEnumMember(null).Should().BeNull(); } [Fact] - public void ConvertValueToEnumMember_NumericValueNotMatchingAnyEnumMemberValue_ShouldThrow() => - Invoking(() => EnumConverter.ConvertValueToEnumMember(999, typeof(TestEnum))) + public void ConvertValueToEnumMemberOfT_NumericValueNotMatchingAnyEnumMemberValue_ShouldThrow() => + Invoking(() => EnumConverter.ConvertValueToEnumMember(999)) .Should() .Throw() .WithMessage( @@ -68,16 +127,16 @@ public void ConvertValueToEnumMember_NumericValueNotMatchingAnyEnumMemberValue_S [Theory] [MemberData(nameof(GetConvertValueToEnumMemberTestData))] - public void ConvertValueToEnumMember_ShouldConvertValueToEnumMember(object value, TestEnum expectedResult) + public void ConvertValueToEnumMemberOfT_ShouldConvertValueToEnumMember(object value, TestEnum expectedResult) { - EnumConverter.ConvertValueToEnumMember(value, typeof(TestEnum)).Should().Be(expectedResult); + EnumConverter.ConvertValueToEnumMember(value).Should().Be(expectedResult); - EnumConverter.ConvertValueToEnumMember(value, typeof(TestEnum?)).Should().Be(expectedResult); + EnumConverter.ConvertValueToEnumMember(value).Should().Be(expectedResult); } [Fact] - public void ConvertValueToEnumMember_StringValueNotMatchingAnyEnumMemberName_ShouldThrow() => - Invoking(() => EnumConverter.ConvertValueToEnumMember("NonExistent", typeof(TestEnum))) + public void ConvertValueToEnumMemberOfT_StringValueNotMatchingAnyEnumMemberName_ShouldThrow() => + Invoking(() => EnumConverter.ConvertValueToEnumMember("NonExistent")) .Should() .Throw() .WithMessage( @@ -86,8 +145,8 @@ public void ConvertValueToEnumMember_StringValueNotMatchingAnyEnumMemberName_Sho ); [Fact] - public void ConvertValueToEnumMember_ValueIsNeitherEnumValueNorStringNorNumeric_ShouldThrow() => - Invoking(() => EnumConverter.ConvertValueToEnumMember(Guid.Empty, typeof(TestEnum))) + public void ConvertValueToEnumMemberOfT_ValueIsNeitherEnumValueNorStringNorNumeric_ShouldThrow() => + Invoking(() => EnumConverter.ConvertValueToEnumMember(Guid.Empty)) .Should() .Throw() .WithMessage( @@ -97,8 +156,8 @@ public void ConvertValueToEnumMember_ValueIsNeitherEnumValueNorStringNorNumeric_ ); [Fact] - public void ConvertValueToEnumMember_ValueIsOfDifferentEnumType_ShouldThrow() => - Invoking(() => EnumConverter.ConvertValueToEnumMember(ConsoleColor.Red, typeof(TestEnum))) + public void ConvertValueToEnumMemberOfT_ValueIsOfDifferentEnumType_ShouldThrow() => + Invoking(() => EnumConverter.ConvertValueToEnumMember(ConsoleColor.Red)) .Should() .Throw() .WithMessage( @@ -108,8 +167,8 @@ public void ConvertValueToEnumMember_ValueIsOfDifferentEnumType_ShouldThrow() => ); [Fact] - public void ConvertValueToEnumMember_WhitespaceStringValue_ShouldThrow() => - Invoking(() => EnumConverter.ConvertValueToEnumMember(" ", typeof(TestEnum))) + public void ConvertValueToEnumMemberOfT_WhitespaceStringValue_ShouldThrow() => + Invoking(() => EnumConverter.ConvertValueToEnumMember(" ")) .Should() .Throw() .WithMessage( @@ -118,8 +177,8 @@ public void ConvertValueToEnumMember_WhitespaceStringValue_ShouldThrow() => ); [Fact] - public void ConvertValueToEnumMemberOfT_EmptyStringValue_ShouldThrow() => - Invoking(() => EnumConverter.ConvertValueToEnumMember(string.Empty)) + public void ConvertValueToEnumMember_EmptyStringValue_ShouldThrow() => + Invoking(() => EnumConverter.ConvertValueToEnumMember(string.Empty, typeof(TestEnum))) .Should() .Throw() .WithMessage( @@ -128,9 +187,9 @@ public void ConvertValueToEnumMemberOfT_EmptyStringValue_ShouldThrow() => ); [Fact] - public void ConvertValueToEnumMemberOfT_NonEnumTargetType_ShouldThrow() + public void ConvertValueToEnumMember_NonEnumTargetType_ShouldThrow() { - Invoking(() => EnumConverter.ConvertValueToEnumMember("ValueA")) + Invoking(() => EnumConverter.ConvertValueToEnumMember("ValueA", typeof(int))) .Should() .Throw() .WithMessage( @@ -138,7 +197,7 @@ public void ConvertValueToEnumMemberOfT_NonEnumTargetType_ShouldThrow() + $"{typeof(int)}, because the type {typeof(int)} is not an enum type.*" ); - Invoking(() => EnumConverter.ConvertValueToEnumMember("ValueA")) + Invoking(() => EnumConverter.ConvertValueToEnumMember("ValueA", typeof(int?))) .Should() .Throw() .WithMessage( @@ -148,30 +207,30 @@ public void ConvertValueToEnumMemberOfT_NonEnumTargetType_ShouldThrow() } [Fact] - public void ConvertValueToEnumMemberOfT_NonNullableTargetType_NullOrDBNullValue_ShouldThrow() + public void ConvertValueToEnumMember_NonNullableTargetType_NullOrDBNullValue_ShouldThrow() { - Invoking(() => EnumConverter.ConvertValueToEnumMember(DBNull.Value)) + Invoking(() => EnumConverter.ConvertValueToEnumMember(DBNull.Value, typeof(TestEnum))) .Should() .Throw() .WithMessage($"Could not convert {{null}} to an enum member of the type {typeof(TestEnum)}."); - Invoking(() => EnumConverter.ConvertValueToEnumMember(null)) + Invoking(() => EnumConverter.ConvertValueToEnumMember(null, typeof(TestEnum))) .Should() .Throw() .WithMessage($"Could not convert {{null}} to an enum member of the type {typeof(TestEnum)}."); } [Fact] - public void ConvertValueToEnumMemberOfT_NullableTargetType_NullOrDBNullValue_ShouldReturnNull() + public void ConvertValueToEnumMember_NullableTargetType_NullOrDBNullValue_ShouldReturnNull() { - EnumConverter.ConvertValueToEnumMember(DBNull.Value).Should().BeNull(); + EnumConverter.ConvertValueToEnumMember(DBNull.Value, typeof(TestEnum?)).Should().BeNull(); - EnumConverter.ConvertValueToEnumMember(null).Should().BeNull(); + EnumConverter.ConvertValueToEnumMember(null, typeof(TestEnum?)).Should().BeNull(); } [Fact] - public void ConvertValueToEnumMemberOfT_NumericValueNotMatchingAnyEnumMemberValue_ShouldThrow() => - Invoking(() => EnumConverter.ConvertValueToEnumMember(999)) + public void ConvertValueToEnumMember_NumericValueNotMatchingAnyEnumMemberValue_ShouldThrow() => + Invoking(() => EnumConverter.ConvertValueToEnumMember(999, typeof(TestEnum))) .Should() .Throw() .WithMessage( @@ -181,16 +240,16 @@ public void ConvertValueToEnumMemberOfT_NumericValueNotMatchingAnyEnumMemberValu [Theory] [MemberData(nameof(GetConvertValueToEnumMemberTestData))] - public void ConvertValueToEnumMemberOfT_ShouldConvertValueToEnumMember(object value, TestEnum expectedResult) + public void ConvertValueToEnumMember_ShouldConvertValueToEnumMember(object value, TestEnum expectedResult) { - EnumConverter.ConvertValueToEnumMember(value).Should().Be(expectedResult); + EnumConverter.ConvertValueToEnumMember(value, typeof(TestEnum)).Should().Be(expectedResult); - EnumConverter.ConvertValueToEnumMember(value).Should().Be(expectedResult); + EnumConverter.ConvertValueToEnumMember(value, typeof(TestEnum?)).Should().Be(expectedResult); } [Fact] - public void ConvertValueToEnumMemberOfT_StringValueNotMatchingAnyEnumMemberName_ShouldThrow() => - Invoking(() => EnumConverter.ConvertValueToEnumMember("NonExistent")) + public void ConvertValueToEnumMember_StringValueNotMatchingAnyEnumMemberName_ShouldThrow() => + Invoking(() => EnumConverter.ConvertValueToEnumMember("NonExistent", typeof(TestEnum))) .Should() .Throw() .WithMessage( @@ -199,8 +258,8 @@ public void ConvertValueToEnumMemberOfT_StringValueNotMatchingAnyEnumMemberName_ ); [Fact] - public void ConvertValueToEnumMemberOfT_ValueIsNeitherEnumValueNorStringNorNumeric_ShouldThrow() => - Invoking(() => EnumConverter.ConvertValueToEnumMember(Guid.Empty)) + public void ConvertValueToEnumMember_ValueIsNeitherEnumValueNorStringNorNumeric_ShouldThrow() => + Invoking(() => EnumConverter.ConvertValueToEnumMember(Guid.Empty, typeof(TestEnum))) .Should() .Throw() .WithMessage( @@ -210,8 +269,8 @@ public void ConvertValueToEnumMemberOfT_ValueIsNeitherEnumValueNorStringNorNumer ); [Fact] - public void ConvertValueToEnumMemberOfT_ValueIsOfDifferentEnumType_ShouldThrow() => - Invoking(() => EnumConverter.ConvertValueToEnumMember(ConsoleColor.Red)) + public void ConvertValueToEnumMember_ValueIsOfDifferentEnumType_ShouldThrow() => + Invoking(() => EnumConverter.ConvertValueToEnumMember(ConsoleColor.Red, typeof(TestEnum))) .Should() .Throw() .WithMessage( @@ -221,71 +280,12 @@ public void ConvertValueToEnumMemberOfT_ValueIsOfDifferentEnumType_ShouldThrow() ); [Fact] - public void ConvertValueToEnumMemberOfT_WhitespaceStringValue_ShouldThrow() => - Invoking(() => EnumConverter.ConvertValueToEnumMember(" ")) + public void ConvertValueToEnumMember_WhitespaceStringValue_ShouldThrow() => + Invoking(() => EnumConverter.ConvertValueToEnumMember(" ", typeof(TestEnum))) .Should() .Throw() .WithMessage( "Could not convert an empty string or a string that consists only of white-space characters to an " + $"enum member of the type {typeof(TestEnum)}." ); - - public static IEnumerable<(object value, TestEnum expectedResult)> GetConvertValueToEnumMemberTestData() => - [ - ((short)1, TestEnum.Value1), - ((short)2, TestEnum.Value2), - ((short)3, TestEnum.Value3), - ((short)4, TestEnum.Value4), - ((short)5, TestEnum.Value5), - (1, TestEnum.Value1), - (2, TestEnum.Value2), - (3, TestEnum.Value3), - (4, TestEnum.Value4), - (5, TestEnum.Value5), - (1L, TestEnum.Value1), - (2L, TestEnum.Value2), - (3L, TestEnum.Value3), - (4L, TestEnum.Value4), - (5L, TestEnum.Value5), - ((byte)1, TestEnum.Value1), - ((byte)2, TestEnum.Value2), - ((byte)3, TestEnum.Value3), - ((byte)4, TestEnum.Value4), - ((byte)5, TestEnum.Value5), - ((float)1.0, TestEnum.Value1), - ((float)2.0, TestEnum.Value2), - ((float)3.0, TestEnum.Value3), - ((float)4.0, TestEnum.Value4), - ((float)5.0, TestEnum.Value5), - (1.0, TestEnum.Value1), - (2.0, TestEnum.Value2), - (3.0, TestEnum.Value3), - (4.0, TestEnum.Value4), - (5.0, TestEnum.Value5), - ((decimal)1.0, TestEnum.Value1), - ((decimal)2.0, TestEnum.Value2), - ((decimal)3.0, TestEnum.Value3), - ((decimal)4.0, TestEnum.Value4), - ((decimal)5.0, TestEnum.Value5), - ("Value1", TestEnum.Value1), - ("Value2", TestEnum.Value2), - ("Value3", TestEnum.Value3), - ("Value4", TestEnum.Value4), - ("Value5", TestEnum.Value5), - ("VALUE1", TestEnum.Value1), - ("VALUE2", TestEnum.Value2), - ("VALUE3", TestEnum.Value3), - ("VALUE4", TestEnum.Value4), - ("VALUE5", TestEnum.Value5), - ("1", TestEnum.Value1), - ("2", TestEnum.Value2), - ("3", TestEnum.Value3), - ("4", TestEnum.Value4), - ("5", TestEnum.Value5), - (TestEnum.Value1, TestEnum.Value1), - (TestEnum.Value2, TestEnum.Value2), - (TestEnum.Value3, TestEnum.Value3), - (TestEnum.Value4, TestEnum.Value4), - (TestEnum.Value5, TestEnum.Value5), - ]; } diff --git a/tests/DbConnectionPlus.UnitTests/Converters/ValueConverterTests.cs b/tests/DbConnectionPlus.UnitTests/Converters/ValueConverterTests.cs index eb4e2c7..65c587a 100644 --- a/tests/DbConnectionPlus.UnitTests/Converters/ValueConverterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Converters/ValueConverterTests.cs @@ -14,695 +14,42 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.Converters; public class ValueConverterTests : UnitTestsBase { - [Theory] - [MemberData(nameof(GetConvertTestData))] - public void CanConvert_NullableSourceType_ShouldDetermineIfConversionIsPossible( - Type sourceType, - Type targetType, - bool expectedCanConvert, - object? sourceValue, - object? expectedTargetValue - ) - { - Assert.SkipUnless(sourceType.IsValueType, ""); - - sourceType = typeof(Nullable<>).MakeGenericType(sourceType); - sourceValue = Activator.CreateInstance(sourceType, sourceValue); - - this.CanConvert_ShouldDetermineIfConversionIsPossible( - sourceType, - targetType, - expectedCanConvert, - sourceValue, - expectedTargetValue - ); - } - - [Theory] - [MemberData(nameof(GetConvertTestData))] - public void CanConvert_NullableTargetType_ShouldDetermineIfConversionIsPossible( - Type sourceType, - Type targetType, - bool expectedCanConvert, - object? sourceValue, - object? expectedTargetValue - ) - { - Assert.SkipUnless(targetType.IsValueType, ""); - - targetType = typeof(Nullable<>).MakeGenericType(targetType); - expectedTargetValue = Activator.CreateInstance(targetType, expectedTargetValue); - - this.CanConvert_ShouldDetermineIfConversionIsPossible( - sourceType, - targetType, - expectedCanConvert, - sourceValue, - expectedTargetValue - ); - } - - [Theory] - [MemberData(nameof(GetConvertTestData))] - public void CanConvert_ShouldDetermineIfConversionIsPossible( - Type sourceType, - Type targetType, - bool expectedCanConvert, -#pragma warning disable xUnit1026 // Theory methods should use all of their parameters -#pragma warning disable RCS1163 // Unused parameter - object? sourceValue, - object? expectedTargetValue -#pragma warning restore RCS1163 // Unused parameter -#pragma warning restore xUnit1026 // Theory methods should use all of their parameters - ) => - ValueConverter - .CanConvert(sourceType, targetType) - .Should() - .Be( - expectedCanConvert, - $"{sourceType} should {(expectedCanConvert ? "" : "not ")}be convertible to {targetType}" - ); - - [Fact] - public void ConvertValueToType_CharTargetType_StringWithLengthOneValue_ShouldGetFirstCharacter() - { - var character = Generate.Single(); - - ValueConverter.ConvertValueToType(character.ToString(), typeof(char)).Should().Be(character); - - ValueConverter.ConvertValueToType(character.ToString(), typeof(char?)).Should().Be(character); - } - - [Fact] - public void ConvertValueToType_CharTargetType_ValueIsStringWithLengthNotOne_ShouldThrow() - { - Invoking(() => ValueConverter.ConvertValueToType(string.Empty, typeof(char))) - .Should() - .Throw() - .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly one " - + "character long." - ); - - Invoking(() => ValueConverter.ConvertValueToType(string.Empty, typeof(char?))) - .Should() - .Throw() - .WithMessage( - $"Could not convert the string '' to the type {typeof(char?)}. The string must be exactly one " - + "character long." - ); - - Invoking(() => ValueConverter.ConvertValueToType("ab", typeof(char))) - .Should() - .Throw() - .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly one " - + "character long." - ); - - Invoking(() => ValueConverter.ConvertValueToType("ab", typeof(char?))) - .Should() - .Throw() - .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char?)}. The string must be exactly one " - + "character long." - ); - } - - [Theory] - [InlineData("de-DE")] - [InlineData("fr-FR")] - [InlineData("en-US")] - public void ConvertValueToType_DateAndTimeStringValue_AmbiguousDate_ShouldNotDependOnTheCurrentCulture( - string cultureName - ) - { - // "03/04/2026" is the 4th of March under en-US and the 3rd of April under de-DE and fr-FR. Read with - // the invariant culture it is the 4th of March everywhere, so one database value can no longer decode - // into two different dates depending on the locale of the machine that runs the code. - var expectedDate = new DateOnly(2026, 3, 4); - - RunUnderCulture( - cultureName, - () => - { - ValueConverter.ConvertValueToType("03/04/2026").Should().Be(expectedDate); - - ValueConverter.ConvertValueToType("03/04/2026", typeof(DateOnly)).Should().Be(expectedDate); - } - ); - } - - [Theory] - [InlineData("de-DE")] - [InlineData("fr-FR")] - [InlineData("en-US")] - public void ConvertValueToType_DateAndTimeStringValue_ShouldRoundTripUnderAnyCulture(string cultureName) - { - // The converter writes these four types with the invariant culture, so it has to read them back the - // same way. It did not: under a culture whose decimal separator is a comma, a TimeSpan this library - // itself had written as "1:2:03:04.567" did not parse back at all, and the conversion threw. - var timeSpan = new TimeSpan(1, 2, 3, 4, 567); - var dateTimeOffset = new DateTimeOffset(2026, 3, 4, 14, 30, 0, TimeSpan.FromHours(2)); - var dateOnly = new DateOnly(2026, 3, 4); - var timeOnly = new TimeOnly(14, 30, 0); - - RunUnderCulture( - cultureName, - () => - { - AssertRoundTrips(timeSpan); - AssertRoundTrips(dateTimeOffset); - AssertRoundTrips(dateOnly); - AssertRoundTrips(timeOnly); - } - ); - - // Converts the value to its String representation and back, both through the converter itself, so the - // assertion is that the writing half and the reading half agree - not that either matches a literal. - static void AssertRoundTrips(TValue value) - { - var text = ValueConverter.ConvertValueToType(value); - - ValueConverter - .ConvertValueToType(text) - .Should() - .Be(value, $"{typeof(TValue)} written as '{text}' should read back unchanged"); - - ValueConverter - .ConvertValueToType(text, typeof(TValue)) - .Should() - .Be(value, $"{typeof(TValue)} written as '{text}' should read back unchanged"); - } - } - - [Fact] - public void ConvertValueToType_EnumTargetType_IntegerValueNotMatchingAnyEnumMemberValue_ShouldThrow() - { - Invoking(() => ValueConverter.ConvertValueToType(999, typeof(TestEnum))) - .Should() - .Throw() - .WithMessage( - $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " - + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" - ); - - Invoking(() => ValueConverter.ConvertValueToType(999, typeof(TestEnum?))) - .Should() - .Throw() - .WithMessage( - $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " - + $"{typeof(TestEnum?)}. That value does not match any of the values of the enum's members.*" - ); - } - - [Fact] - public void ConvertValueToType_EnumTargetType_ShouldConvertToEnumMember() + public static IEnumerable<( + Type SourceType, + Type TargetType, + bool ExpectedCanConvert, + object SourceValue, + object ExpectedTargetValue + )> GetConvertTestData() { - var enumValue = Generate.Single(); - - ValueConverter.ConvertValueToType((int)enumValue, typeof(TestEnum)).Should().Be(enumValue); + var faker = new Faker(); - ValueConverter.ConvertValueToType((int)enumValue, typeof(TestEnum?)).Should().Be(enumValue); - } + // All numeric values are kept within the range 0-127 so they are convertible to the smallest target type + // (SByte) without overflow. + var byteValue = faker.Random.Byte(0, 127); + var charValue = faker.Random.Char('A', 'Z'); + var dateOnlyValue = faker.Date.PastDateOnly(); + var dateTimeValue = faker.Date.Past(); + var dateTimeOffsetValue = faker.Date.PastOffset(); + var decimalValue = faker.Random.Decimal(0, 127); + var doubleValue = faker.Random.Double(0, 127); + var guidValue = faker.Random.Guid(); + var int16Value = faker.Random.Short(0, 127); + var int32Value = faker.Random.Int(0, 127); + var int64Value = faker.Random.Long(0, 127); + var intPtrValue = (IntPtr)faker.Random.Int(0, 127); + var sbyteValue = faker.Random.SByte(0); + var singleValue = faker.Random.Float(0, 127); + var stringValue = faker.Lorem.Sentence(); + var uint16Value = faker.Random.UShort(0, 127); + var uint32Value = faker.Random.UInt(0, 127); + var uint64Value = faker.Random.ULong(0, 127); + var timeSpanValue = faker.Date.Timespan(TimeSpan.FromHours(23)); + var timeOnlyValue = faker.Date.RecentTimeOnly(); + var uintPtrValue = (UIntPtr)faker.Random.Int(0, 127); + var enumValue = faker.Random.Enum(); - [Fact] - public void ConvertValueToType_EnumTargetType_StringValueNotMatchingAnyEnumMemberName_ShouldThrow() - { - Invoking(() => ValueConverter.ConvertValueToType("NonExistent", typeof(TestEnum))) - .Should() - .Throw() - .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " - + "That string does not match any of the names of the enum's members.*" - ); - - Invoking(() => ValueConverter.ConvertValueToType("NonExistent", typeof(TestEnum?))) - .Should() - .Throw() - .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum?)}. " - + "That string does not match any of the names of the enum's members.*" - ); - } - - [Fact] - public void ConvertValueToType_NonNullableTargetType_NullOrDBNullValue_ShouldThrow() - { - Invoking(() => ValueConverter.ConvertValueToType(DBNull.Value, typeof(DateTime))) - .Should() - .Throw() - .WithMessage( - $"Could not convert the value {{DBNull}} to the type {typeof(DateTime)}, because the " - + "type is non-nullable.*" - ); - - Invoking(() => ValueConverter.ConvertValueToType(null, typeof(DateTime))) - .Should() - .Throw() - .WithMessage( - $"Could not convert the value {{null}} to the type {typeof(DateTime)}, because the type is " - + "non-nullable.*" - ); - } - - [Theory] - [MemberData(nameof(GetConvertTestData))] - public void ConvertValueToType_NullableSourceType_ShouldConvertValueToTargetType( - Type sourceType, - Type targetType, - bool expectedCanConvert, - object? sourceValue, - object? expectedTargetValue - ) - { - Assert.SkipUnless(sourceType.IsValueType, ""); - - sourceType = typeof(Nullable<>).MakeGenericType(sourceType); - sourceValue = Activator.CreateInstance(sourceType, sourceValue); - - this.ConvertValueToType_ShouldConvertValueToType( - sourceType, - targetType, - expectedCanConvert, - sourceValue, - expectedTargetValue - ); - } - - [Fact] - public void ConvertValueToType_NullableTargetType_NullOrDBNullValue_ShouldReturnNull() - { - ValueConverter.ConvertValueToType(DBNull.Value, typeof(object)).Should().BeNull(); - - ValueConverter.ConvertValueToType(DBNull.Value, typeof(int?)).Should().BeNull(); - - ValueConverter.ConvertValueToType(null, typeof(object)).Should().BeNull(); - - ValueConverter.ConvertValueToType(null, typeof(int?)).Should().BeNull(); - } - - [Theory] - [MemberData(nameof(GetConvertTestData))] - public void ConvertValueToType_NullableTargetType_ShouldConvertValueToTargetType( - Type sourceType, - Type targetType, - bool expectedCanConvert, - object? sourceValue, - object? expectedTargetValue - ) - { - Assert.SkipUnless(targetType.IsValueType, ""); - - targetType = typeof(Nullable<>).MakeGenericType(targetType); - expectedTargetValue = Activator.CreateInstance(targetType, expectedTargetValue); - - this.ConvertValueToType_ShouldConvertValueToType( - sourceType, - targetType, - expectedCanConvert, - sourceValue, - expectedTargetValue - ); - } - - [Theory] - [MemberData(nameof(GetConvertTestData))] - public void ConvertValueToType_ShouldConvertValueToType( - Type _, - Type targetType, - bool expectedCanConvert, - object? sourceValue, - object? expectedTargetValue - ) - { - if (expectedCanConvert) - { - var result = ValueConverter.ConvertValueToType(sourceValue, targetType); - - if (result is byte[] resultBytes && expectedTargetValue is byte[] expectedTargetValueBytes) - { - resultBytes - .Should() - .BeEquivalentTo( - expectedTargetValueBytes, - $"{sourceValue.ToDebugString()} converted to {targetType} should be " - + $"{expectedTargetValue.ToDebugString()}" - ); - } - else - { - result - .Should() - .Be( - expectedTargetValue, - $"{sourceValue.ToDebugString()} converted to {targetType} should be " - + $"{expectedTargetValue.ToDebugString()}" - ); - } - } - else - { - Invoking(() => ValueConverter.ConvertValueToType(sourceValue, targetType)) - .Should() - .Throw() - .WithMessage($"Could not convert the value {sourceValue.ToDebugString()} to the type {targetType}.*"); - } - } - - [Fact] - public void ConvertValueToType_ValueCannotBeConvertedToTargetType_ShouldThrow() => - Invoking(() => ValueConverter.ConvertValueToType("NotADate", typeof(DateTime))) - .Should() - .Throw() - .WithMessage( - $"Could not convert the value 'NotADate' ({typeof(string)}) to the type {typeof(DateTime)}. See " - + "inner exception for details.*" - ) - .WithInnerException() - .WithMessage("The string 'NotADate' was not recognized as a valid DateTime.*"); - - [Fact] - public void ConvertValueToTypeOfT_CharTargetType_StringWithLengthOneValue_ShouldGetFirstCharacter() - { - var character = Generate.Single(); - - ValueConverter.ConvertValueToType(character.ToString()).Should().Be(character); - - ValueConverter.ConvertValueToType(character.ToString()).Should().Be(character); - } - - [Fact] - public void ConvertValueToTypeOfT_CharTargetType_ValueIsStringWithLengthNotOne_ShouldThrow() - { - Invoking(() => ValueConverter.ConvertValueToType(string.Empty)) - .Should() - .Throw() - .WithMessage( - $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly one " - + "character long." - ); - - Invoking(() => ValueConverter.ConvertValueToType(string.Empty)) - .Should() - .Throw() - .WithMessage( - $"Could not convert the string '' to the type {typeof(char?)}. The string must be exactly one " - + "character long." - ); - - Invoking(() => ValueConverter.ConvertValueToType("ab")) - .Should() - .Throw() - .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly one " - + "character long." - ); - - Invoking(() => ValueConverter.ConvertValueToType("ab")) - .Should() - .Throw() - .WithMessage( - $"Could not convert the string 'ab' to the type {typeof(char?)}. The string must be exactly one " - + "character long." - ); - } - - [Fact] - public void ConvertValueToTypeOfT_EnumTargetType_IntegerValueNotMatchingAnyEnumMemberValue_ShouldThrow() - { - Invoking(() => ValueConverter.ConvertValueToType(999)) - .Should() - .Throw() - .WithMessage( - $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " - + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" - ); - - Invoking(() => ValueConverter.ConvertValueToType(999)) - .Should() - .Throw() - .WithMessage( - $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " - + $"{typeof(TestEnum?)}. That value does not match any of the values of the enum's members.*" - ); - } - - [Fact] - public void ConvertValueToTypeOfT_EnumTargetType_ShouldConvertToEnumMember() - { - var enumValue = Generate.Single(); - - ValueConverter.ConvertValueToType((int)enumValue).Should().Be(enumValue); - - ValueConverter.ConvertValueToType((int)enumValue).Should().Be(enumValue); - } - - [Fact] - public void ConvertValueToTypeOfT_EnumTargetType_StringValueNotMatchingAnyEnumMemberName_ShouldThrow() - { - Invoking(() => ValueConverter.ConvertValueToType("NonExistent")) - .Should() - .Throw() - .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " - + "That string does not match any of the names of the enum's members.*" - ); - - Invoking(() => ValueConverter.ConvertValueToType("NonExistent")) - .Should() - .Throw() - .WithMessage( - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum?)}. " - + "That string does not match any of the names of the enum's members.*" - ); - } - - [Fact] - public void ConvertValueToTypeOfT_NonNullableTargetType_NullOrDBNullValue_ShouldThrow() - { - Invoking(() => ValueConverter.ConvertValueToType(DBNull.Value)) - .Should() - .Throw() - .WithMessage( - $"Could not convert the value {{DBNull}} to the type {typeof(DateTime)}, because the " - + "type is non-nullable.*" - ); - - Invoking(() => ValueConverter.ConvertValueToType(null)) - .Should() - .Throw() - .WithMessage( - $"Could not convert the value {{null}} to the type {typeof(DateTime)}, because the type is " - + "non-nullable.*" - ); - } - - [Theory] - [MemberData(nameof(GetConvertTestData))] - public void ConvertValueToTypeOfT_NullableSourceType_ShouldConvertValueToTargetType( - Type sourceType, - Type targetType, - bool expectedCanConvert, - object? sourceValue, - object? expectedTargetValue - ) - { - Assert.SkipUnless(sourceType.IsValueType, ""); - - sourceType = typeof(Nullable<>).MakeGenericType(sourceType); - sourceValue = Activator.CreateInstance(sourceType, sourceValue); - - this.ConvertValueToTypeOfT_ShouldConvertValueToType( - sourceType, - targetType, - expectedCanConvert, - sourceValue, - expectedTargetValue - ); - } - - [Fact] - public void ConvertValueToTypeOfT_NullableTargetType_NullOrDBNullValue_ShouldReturnNull() - { - ValueConverter.ConvertValueToType(DBNull.Value).Should().BeNull(); - - ValueConverter.ConvertValueToType(DBNull.Value).Should().BeNull(); - - ValueConverter.ConvertValueToType(null).Should().BeNull(); - - ValueConverter.ConvertValueToType(null).Should().BeNull(); - } - - [Theory] - [MemberData(nameof(GetConvertTestData))] - public void ConvertValueToTypeOfT_NullableTargetType_ShouldConvertValueToTargetType( - Type sourceType, - Type targetType, - bool expectedCanConvert, - object? sourceValue, - object? expectedTargetValue - ) - { - Assert.SkipUnless(targetType.IsValueType, ""); - - targetType = typeof(Nullable<>).MakeGenericType(targetType); - expectedTargetValue = Activator.CreateInstance(targetType, expectedTargetValue); - - this.ConvertValueToTypeOfT_ShouldConvertValueToType( - sourceType, - targetType, - expectedCanConvert, - sourceValue, - expectedTargetValue - ); - } - - [Theory] - [MemberData(nameof(GetConvertTestData))] - public void ConvertValueToTypeOfT_ShouldConvertValueToType( - Type _, - Type targetType, - bool expectedCanConvert, - object? sourceValue, - object? expectedTargetValue - ) - { - if (expectedCanConvert) - { - var result = MaterializerFactoryHelper - .MakeValueConverterConvertValueToTypeMethod(targetType) - .Invoke(null, [sourceValue]); - - if (result is byte[] resultBytes && expectedTargetValue is byte[] expectedTargetValueBytes) - { - resultBytes - .Should() - .BeEquivalentTo( - expectedTargetValueBytes, - $"{sourceValue.ToDebugString()} converted to {targetType} should be " - + $"{expectedTargetValue.ToDebugString()}" - ); - } - else - { - result - .Should() - .Be( - expectedTargetValue, - $"{sourceValue.ToDebugString()} converted to {targetType} should be " - + $"{expectedTargetValue.ToDebugString()}" - ); - } - } - else - { - Invoking(() => - MaterializerFactoryHelper - .MakeValueConverterConvertValueToTypeMethod(targetType) - .Invoke(null, [sourceValue]) - ) - .Should() - .Throw() - .WithInnerException() - .WithMessage($"Could not convert the value {sourceValue.ToDebugString()} to the type {targetType}.*"); - } - } - - [Fact] - public void ConvertValueToTypeOfT_ValueCannotBeConvertedToTargetType_ShouldThrow() => - Invoking(() => ValueConverter.ConvertValueToType("NotADate")) - .Should() - .Throw() - .WithMessage( - $"Could not convert the value 'NotADate' ({typeof(string)}) to the type {typeof(DateTime)}. See " - + "inner exception for details.*" - ) - .WithInnerException() - .WithMessage("The string 'NotADate' was not recognized as a valid DateTime.*"); - - [Fact] - public void ShouldGuardAgainstNullArguments() - { - ArgumentNullGuardVerifier.Verify(() => ValueConverter.CanConvert(typeof(short), typeof(int))); - ArgumentNullGuardVerifier.Verify(() => ValueConverter.ConvertValueToType(1, typeof(int))); - } - - /// - /// Runs with the current culture set to , - /// and restores the previous culture afterwards. - /// - /// - /// pins every test to en-US, and en-US is exactly the culture under which - /// culture-dependent date and time parsing still looks correct - which is why the whole suite passed - /// while the converter was reading with the current culture. A test for that has to leave the pin. - /// The assembly runs with ParallelMode.None, so changing the culture cannot affect another test. - /// - /// The name of the culture to run the assertions under. - /// The assertions to run. - private static void RunUnderCulture(string cultureName, Action assertions) - { - var culture = new CultureInfo(cultureName); - - // Without ICU, every culture collapses into the invariant one and the test would pass while proving - // nothing. de-DE and fr-FR both separate decimals with a comma; the invariant culture uses a dot. - Assert.SkipWhen( - cultureName != "en-US" - && culture.NumberFormat.NumberDecimalSeparator - == CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator, - $"Globalization is in invariant mode, so '{cultureName}' is not a real culture here." - ); - - var previousCulture = CultureInfo.CurrentCulture; - - CultureInfo.CurrentCulture = Thread.CurrentThread.CurrentCulture = culture; - - try - { - assertions(); - } - finally - { - CultureInfo.CurrentCulture = Thread.CurrentThread.CurrentCulture = previousCulture; - } - } - - public static IEnumerable<( - Type SourceType, - Type TargetType, - bool ExpectedCanConvert, - object SourceValue, - object ExpectedTargetValue - )> GetConvertTestData() - { - var faker = new Faker(); - - // All numeric values are kept within the range 0-127 so they are convertible to the smallest target type - // (SByte) without overflow. - var byteValue = faker.Random.Byte(0, 127); - var charValue = faker.Random.Char('A', 'Z'); - var dateOnlyValue = faker.Date.PastDateOnly(); - var dateTimeValue = faker.Date.Past(); - var dateTimeOffsetValue = faker.Date.PastOffset(); - var decimalValue = faker.Random.Decimal(0, 127); - var doubleValue = faker.Random.Double(0, 127); - var guidValue = faker.Random.Guid(); - var int16Value = faker.Random.Short(0, 127); - var int32Value = faker.Random.Int(0, 127); - var int64Value = faker.Random.Long(0, 127); - var intPtrValue = (IntPtr)faker.Random.Int(0, 127); - var sbyteValue = faker.Random.SByte(0); - var singleValue = faker.Random.Float(0, 127); - var stringValue = faker.Lorem.Sentence(); - var uint16Value = faker.Random.UShort(0, 127); - var uint32Value = faker.Random.UInt(0, 127); - var uint64Value = faker.Random.ULong(0, 127); - var timeSpanValue = faker.Date.Timespan(TimeSpan.FromHours(23)); - var timeOnlyValue = faker.Date.RecentTimeOnly(); - var uintPtrValue = (UIntPtr)faker.Random.Int(0, 127); - var enumValue = faker.Random.Enum(); - - // @formatter:off + // @formatter:off return [ @@ -1215,6 +562,659 @@ object ExpectedTargetValue (typeof(TimeOnly), typeof(Guid), false, timeOnlyValue, null), ]; - // @formatter:on + // @formatter:on + } + + [Theory] + [MemberData(nameof(GetConvertTestData))] + public void CanConvert_NullableSourceType_ShouldDetermineIfConversionIsPossible( + Type sourceType, + Type targetType, + bool expectedCanConvert, + object? sourceValue, + object? expectedTargetValue + ) + { + Assert.SkipUnless(sourceType.IsValueType, ""); + + sourceType = typeof(Nullable<>).MakeGenericType(sourceType); + sourceValue = Activator.CreateInstance(sourceType, sourceValue); + + this.CanConvert_ShouldDetermineIfConversionIsPossible( + sourceType, + targetType, + expectedCanConvert, + sourceValue, + expectedTargetValue + ); + } + + [Theory] + [MemberData(nameof(GetConvertTestData))] + public void CanConvert_NullableTargetType_ShouldDetermineIfConversionIsPossible( + Type sourceType, + Type targetType, + bool expectedCanConvert, + object? sourceValue, + object? expectedTargetValue + ) + { + Assert.SkipUnless(targetType.IsValueType, ""); + + targetType = typeof(Nullable<>).MakeGenericType(targetType); + expectedTargetValue = Activator.CreateInstance(targetType, expectedTargetValue); + + this.CanConvert_ShouldDetermineIfConversionIsPossible( + sourceType, + targetType, + expectedCanConvert, + sourceValue, + expectedTargetValue + ); + } + + [Theory] + [MemberData(nameof(GetConvertTestData))] + public void CanConvert_ShouldDetermineIfConversionIsPossible( + Type sourceType, + Type targetType, + bool expectedCanConvert, +#pragma warning disable xUnit1026 // Theory methods should use all of their parameters +#pragma warning disable RCS1163 // Unused parameter + object? sourceValue, + object? expectedTargetValue +#pragma warning restore RCS1163 // Unused parameter +#pragma warning restore xUnit1026 // Theory methods should use all of their parameters + ) => + ValueConverter + .CanConvert(sourceType, targetType) + .Should() + .Be( + expectedCanConvert, + $"{sourceType} should {(expectedCanConvert ? "" : "not ")}be convertible to {targetType}" + ); + + [Fact] + public void ConvertValueToTypeOfT_CharTargetType_StringWithLengthOneValue_ShouldGetFirstCharacter() + { + var character = Generate.Single(); + + ValueConverter.ConvertValueToType(character.ToString()).Should().Be(character); + + ValueConverter.ConvertValueToType(character.ToString()).Should().Be(character); + } + + [Fact] + public void ConvertValueToTypeOfT_CharTargetType_ValueIsStringWithLengthNotOne_ShouldThrow() + { + Invoking(() => ValueConverter.ConvertValueToType(string.Empty)) + .Should() + .Throw() + .WithMessage( + $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly one " + + "character long." + ); + + Invoking(() => ValueConverter.ConvertValueToType(string.Empty)) + .Should() + .Throw() + .WithMessage( + $"Could not convert the string '' to the type {typeof(char?)}. The string must be exactly one " + + "character long." + ); + + Invoking(() => ValueConverter.ConvertValueToType("ab")) + .Should() + .Throw() + .WithMessage( + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly one " + + "character long." + ); + + Invoking(() => ValueConverter.ConvertValueToType("ab")) + .Should() + .Throw() + .WithMessage( + $"Could not convert the string 'ab' to the type {typeof(char?)}. The string must be exactly one " + + "character long." + ); + } + + [Fact] + public void ConvertValueToTypeOfT_EnumTargetType_IntegerValueNotMatchingAnyEnumMemberValue_ShouldThrow() + { + Invoking(() => ValueConverter.ConvertValueToType(999)) + .Should() + .Throw() + .WithMessage( + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" + ); + + Invoking(() => ValueConverter.ConvertValueToType(999)) + .Should() + .Throw() + .WithMessage( + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + + $"{typeof(TestEnum?)}. That value does not match any of the values of the enum's members.*" + ); + } + + [Fact] + public void ConvertValueToTypeOfT_EnumTargetType_ShouldConvertToEnumMember() + { + var enumValue = Generate.Single(); + + ValueConverter.ConvertValueToType((int)enumValue).Should().Be(enumValue); + + ValueConverter.ConvertValueToType((int)enumValue).Should().Be(enumValue); + } + + [Fact] + public void ConvertValueToTypeOfT_EnumTargetType_StringValueNotMatchingAnyEnumMemberName_ShouldThrow() + { + Invoking(() => ValueConverter.ConvertValueToType("NonExistent")) + .Should() + .Throw() + .WithMessage( + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + + "That string does not match any of the names of the enum's members.*" + ); + + Invoking(() => ValueConverter.ConvertValueToType("NonExistent")) + .Should() + .Throw() + .WithMessage( + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum?)}. " + + "That string does not match any of the names of the enum's members.*" + ); + } + + [Fact] + public void ConvertValueToTypeOfT_NonNullableTargetType_NullOrDBNullValue_ShouldThrow() + { + Invoking(() => ValueConverter.ConvertValueToType(DBNull.Value)) + .Should() + .Throw() + .WithMessage( + $"Could not convert the value {{DBNull}} to the type {typeof(DateTime)}, because the " + + "type is non-nullable.*" + ); + + Invoking(() => ValueConverter.ConvertValueToType(null)) + .Should() + .Throw() + .WithMessage( + $"Could not convert the value {{null}} to the type {typeof(DateTime)}, because the type is " + + "non-nullable.*" + ); + } + + [Theory] + [MemberData(nameof(GetConvertTestData))] + public void ConvertValueToTypeOfT_NullableSourceType_ShouldConvertValueToTargetType( + Type sourceType, + Type targetType, + bool expectedCanConvert, + object? sourceValue, + object? expectedTargetValue + ) + { + Assert.SkipUnless(sourceType.IsValueType, ""); + + sourceType = typeof(Nullable<>).MakeGenericType(sourceType); + sourceValue = Activator.CreateInstance(sourceType, sourceValue); + + this.ConvertValueToTypeOfT_ShouldConvertValueToType( + sourceType, + targetType, + expectedCanConvert, + sourceValue, + expectedTargetValue + ); + } + + [Fact] + public void ConvertValueToTypeOfT_NullableTargetType_NullOrDBNullValue_ShouldReturnNull() + { + ValueConverter.ConvertValueToType(DBNull.Value).Should().BeNull(); + + ValueConverter.ConvertValueToType(DBNull.Value).Should().BeNull(); + + ValueConverter.ConvertValueToType(null).Should().BeNull(); + + ValueConverter.ConvertValueToType(null).Should().BeNull(); + } + + [Theory] + [MemberData(nameof(GetConvertTestData))] + public void ConvertValueToTypeOfT_NullableTargetType_ShouldConvertValueToTargetType( + Type sourceType, + Type targetType, + bool expectedCanConvert, + object? sourceValue, + object? expectedTargetValue + ) + { + Assert.SkipUnless(targetType.IsValueType, ""); + + targetType = typeof(Nullable<>).MakeGenericType(targetType); + expectedTargetValue = Activator.CreateInstance(targetType, expectedTargetValue); + + this.ConvertValueToTypeOfT_ShouldConvertValueToType( + sourceType, + targetType, + expectedCanConvert, + sourceValue, + expectedTargetValue + ); + } + + [Theory] + [MemberData(nameof(GetConvertTestData))] + public void ConvertValueToTypeOfT_ShouldConvertValueToType( + Type _, + Type targetType, + bool expectedCanConvert, + object? sourceValue, + object? expectedTargetValue + ) + { + if (expectedCanConvert) + { + var result = MaterializerFactoryHelper + .MakeValueConverterConvertValueToTypeMethod(targetType) + .Invoke(null, [sourceValue]); + + if (result is byte[] resultBytes && expectedTargetValue is byte[] expectedTargetValueBytes) + { + resultBytes + .Should() + .BeEquivalentTo( + expectedTargetValueBytes, + $"{sourceValue.ToDebugString()} converted to {targetType} should be " + + $"{expectedTargetValue.ToDebugString()}" + ); + } + else + { + result + .Should() + .Be( + expectedTargetValue, + $"{sourceValue.ToDebugString()} converted to {targetType} should be " + + $"{expectedTargetValue.ToDebugString()}" + ); + } + } + else + { + Invoking(() => + MaterializerFactoryHelper + .MakeValueConverterConvertValueToTypeMethod(targetType) + .Invoke(null, [sourceValue]) + ) + .Should() + .Throw() + .WithInnerException() + .WithMessage($"Could not convert the value {sourceValue.ToDebugString()} to the type {targetType}.*"); + } + } + + [Fact] + public void ConvertValueToTypeOfT_ValueCannotBeConvertedToTargetType_ShouldThrow() => + Invoking(() => ValueConverter.ConvertValueToType("NotADate")) + .Should() + .Throw() + .WithMessage( + $"Could not convert the value 'NotADate' ({typeof(string)}) to the type {typeof(DateTime)}. See " + + "inner exception for details.*" + ) + .WithInnerException() + .WithMessage("The string 'NotADate' was not recognized as a valid DateTime.*"); + + [Fact] + public void ConvertValueToType_CharTargetType_StringWithLengthOneValue_ShouldGetFirstCharacter() + { + var character = Generate.Single(); + + ValueConverter.ConvertValueToType(character.ToString(), typeof(char)).Should().Be(character); + + ValueConverter.ConvertValueToType(character.ToString(), typeof(char?)).Should().Be(character); + } + + [Fact] + public void ConvertValueToType_CharTargetType_ValueIsStringWithLengthNotOne_ShouldThrow() + { + Invoking(() => ValueConverter.ConvertValueToType(string.Empty, typeof(char))) + .Should() + .Throw() + .WithMessage( + $"Could not convert the string '' to the type {typeof(char)}. The string must be exactly one " + + "character long." + ); + + Invoking(() => ValueConverter.ConvertValueToType(string.Empty, typeof(char?))) + .Should() + .Throw() + .WithMessage( + $"Could not convert the string '' to the type {typeof(char?)}. The string must be exactly one " + + "character long." + ); + + Invoking(() => ValueConverter.ConvertValueToType("ab", typeof(char))) + .Should() + .Throw() + .WithMessage( + $"Could not convert the string 'ab' to the type {typeof(char)}. The string must be exactly one " + + "character long." + ); + + Invoking(() => ValueConverter.ConvertValueToType("ab", typeof(char?))) + .Should() + .Throw() + .WithMessage( + $"Could not convert the string 'ab' to the type {typeof(char?)}. The string must be exactly one " + + "character long." + ); + } + + [Theory] + [InlineData("de-DE")] + [InlineData("fr-FR")] + [InlineData("en-US")] + public void ConvertValueToType_DateAndTimeStringValue_AmbiguousDate_ShouldNotDependOnTheCurrentCulture( + string cultureName + ) + { + // "03/04/2026" is the 4th of March under en-US and the 3rd of April under de-DE and fr-FR. Read with + // the invariant culture it is the 4th of March everywhere, so one database value can no longer decode + // into two different dates depending on the locale of the machine that runs the code. + var expectedDate = new DateOnly(2026, 3, 4); + + RunUnderCulture( + cultureName, + () => + { + ValueConverter.ConvertValueToType("03/04/2026").Should().Be(expectedDate); + + ValueConverter.ConvertValueToType("03/04/2026", typeof(DateOnly)).Should().Be(expectedDate); + } + ); + } + + [Theory] + [InlineData("de-DE")] + [InlineData("fr-FR")] + [InlineData("en-US")] + public void ConvertValueToType_DateAndTimeStringValue_ShouldRoundTripUnderAnyCulture(string cultureName) + { + // The converter writes these four types with the invariant culture, so it has to read them back the + // same way. It did not: under a culture whose decimal separator is a comma, a TimeSpan this library + // itself had written as "1:2:03:04.567" did not parse back at all, and the conversion threw. + var timeSpan = new TimeSpan(1, 2, 3, 4, 567); + var dateTimeOffset = new DateTimeOffset(2026, 3, 4, 14, 30, 0, TimeSpan.FromHours(2)); + var dateOnly = new DateOnly(2026, 3, 4); + var timeOnly = new TimeOnly(14, 30, 0); + + RunUnderCulture( + cultureName, + () => + { + AssertRoundTrips(timeSpan); + AssertRoundTrips(dateTimeOffset); + AssertRoundTrips(dateOnly); + AssertRoundTrips(timeOnly); + } + ); + + // Converts the value to its String representation and back, both through the converter itself, so the + // assertion is that the writing half and the reading half agree - not that either matches a literal. + static void AssertRoundTrips(TValue value) + { + var text = ValueConverter.ConvertValueToType(value); + + ValueConverter + .ConvertValueToType(text) + .Should() + .Be(value, $"{typeof(TValue)} written as '{text}' should read back unchanged"); + + ValueConverter + .ConvertValueToType(text, typeof(TValue)) + .Should() + .Be(value, $"{typeof(TValue)} written as '{text}' should read back unchanged"); + } + } + + [Fact] + public void ConvertValueToType_EnumTargetType_IntegerValueNotMatchingAnyEnumMemberValue_ShouldThrow() + { + Invoking(() => ValueConverter.ConvertValueToType(999, typeof(TestEnum))) + .Should() + .Throw() + .WithMessage( + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" + ); + + Invoking(() => ValueConverter.ConvertValueToType(999, typeof(TestEnum?))) + .Should() + .Throw() + .WithMessage( + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + + $"{typeof(TestEnum?)}. That value does not match any of the values of the enum's members.*" + ); + } + + [Fact] + public void ConvertValueToType_EnumTargetType_ShouldConvertToEnumMember() + { + var enumValue = Generate.Single(); + + ValueConverter.ConvertValueToType((int)enumValue, typeof(TestEnum)).Should().Be(enumValue); + + ValueConverter.ConvertValueToType((int)enumValue, typeof(TestEnum?)).Should().Be(enumValue); + } + + [Fact] + public void ConvertValueToType_EnumTargetType_StringValueNotMatchingAnyEnumMemberName_ShouldThrow() + { + Invoking(() => ValueConverter.ConvertValueToType("NonExistent", typeof(TestEnum))) + .Should() + .Throw() + .WithMessage( + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. " + + "That string does not match any of the names of the enum's members.*" + ); + + Invoking(() => ValueConverter.ConvertValueToType("NonExistent", typeof(TestEnum?))) + .Should() + .Throw() + .WithMessage( + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum?)}. " + + "That string does not match any of the names of the enum's members.*" + ); + } + + [Fact] + public void ConvertValueToType_NonNullableTargetType_NullOrDBNullValue_ShouldThrow() + { + Invoking(() => ValueConverter.ConvertValueToType(DBNull.Value, typeof(DateTime))) + .Should() + .Throw() + .WithMessage( + $"Could not convert the value {{DBNull}} to the type {typeof(DateTime)}, because the " + + "type is non-nullable.*" + ); + + Invoking(() => ValueConverter.ConvertValueToType(null, typeof(DateTime))) + .Should() + .Throw() + .WithMessage( + $"Could not convert the value {{null}} to the type {typeof(DateTime)}, because the type is " + + "non-nullable.*" + ); + } + + [Theory] + [MemberData(nameof(GetConvertTestData))] + public void ConvertValueToType_NullableSourceType_ShouldConvertValueToTargetType( + Type sourceType, + Type targetType, + bool expectedCanConvert, + object? sourceValue, + object? expectedTargetValue + ) + { + Assert.SkipUnless(sourceType.IsValueType, ""); + + sourceType = typeof(Nullable<>).MakeGenericType(sourceType); + sourceValue = Activator.CreateInstance(sourceType, sourceValue); + + this.ConvertValueToType_ShouldConvertValueToType( + sourceType, + targetType, + expectedCanConvert, + sourceValue, + expectedTargetValue + ); + } + + [Fact] + public void ConvertValueToType_NullableTargetType_NullOrDBNullValue_ShouldReturnNull() + { + ValueConverter.ConvertValueToType(DBNull.Value, typeof(object)).Should().BeNull(); + + ValueConverter.ConvertValueToType(DBNull.Value, typeof(int?)).Should().BeNull(); + + ValueConverter.ConvertValueToType(null, typeof(object)).Should().BeNull(); + + ValueConverter.ConvertValueToType(null, typeof(int?)).Should().BeNull(); + } + + [Theory] + [MemberData(nameof(GetConvertTestData))] + public void ConvertValueToType_NullableTargetType_ShouldConvertValueToTargetType( + Type sourceType, + Type targetType, + bool expectedCanConvert, + object? sourceValue, + object? expectedTargetValue + ) + { + Assert.SkipUnless(targetType.IsValueType, ""); + + targetType = typeof(Nullable<>).MakeGenericType(targetType); + expectedTargetValue = Activator.CreateInstance(targetType, expectedTargetValue); + + this.ConvertValueToType_ShouldConvertValueToType( + sourceType, + targetType, + expectedCanConvert, + sourceValue, + expectedTargetValue + ); + } + + [Theory] + [MemberData(nameof(GetConvertTestData))] + public void ConvertValueToType_ShouldConvertValueToType( + Type _, + Type targetType, + bool expectedCanConvert, + object? sourceValue, + object? expectedTargetValue + ) + { + if (expectedCanConvert) + { + var result = ValueConverter.ConvertValueToType(sourceValue, targetType); + + if (result is byte[] resultBytes && expectedTargetValue is byte[] expectedTargetValueBytes) + { + resultBytes + .Should() + .BeEquivalentTo( + expectedTargetValueBytes, + $"{sourceValue.ToDebugString()} converted to {targetType} should be " + + $"{expectedTargetValue.ToDebugString()}" + ); + } + else + { + result + .Should() + .Be( + expectedTargetValue, + $"{sourceValue.ToDebugString()} converted to {targetType} should be " + + $"{expectedTargetValue.ToDebugString()}" + ); + } + } + else + { + Invoking(() => ValueConverter.ConvertValueToType(sourceValue, targetType)) + .Should() + .Throw() + .WithMessage($"Could not convert the value {sourceValue.ToDebugString()} to the type {targetType}.*"); + } + } + + [Fact] + public void ConvertValueToType_ValueCannotBeConvertedToTargetType_ShouldThrow() => + Invoking(() => ValueConverter.ConvertValueToType("NotADate", typeof(DateTime))) + .Should() + .Throw() + .WithMessage( + $"Could not convert the value 'NotADate' ({typeof(string)}) to the type {typeof(DateTime)}. See " + + "inner exception for details.*" + ) + .WithInnerException() + .WithMessage("The string 'NotADate' was not recognized as a valid DateTime.*"); + + [Fact] + public void ShouldGuardAgainstNullArguments() + { + ArgumentNullGuardVerifier.Verify(() => ValueConverter.CanConvert(typeof(short), typeof(int))); + ArgumentNullGuardVerifier.Verify(() => ValueConverter.ConvertValueToType(1, typeof(int))); + } + + /// + /// Runs with the current culture set to , + /// and restores the previous culture afterwards. + /// + /// + /// pins every test to en-US, and en-US is exactly the culture under which + /// culture-dependent date and time parsing still looks correct - which is why the whole suite passed + /// while the converter was reading with the current culture. A test for that has to leave the pin. + /// The assembly runs with ParallelMode.None, so changing the culture cannot affect another test. + /// + /// The name of the culture to run the assertions under. + /// The assertions to run. + private static void RunUnderCulture(string cultureName, Action assertions) + { + var culture = new CultureInfo(cultureName); + + // Without ICU, every culture collapses into the invariant one and the test would pass while proving + // nothing. de-DE and fr-FR both separate decimals with a comma; the invariant culture uses a dot. + Assert.SkipWhen( + cultureName != "en-US" + && culture.NumberFormat.NumberDecimalSeparator + == CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator, + $"Globalization is in invariant mode, so '{cultureName}' is not a real culture here." + ); + + var previousCulture = CultureInfo.CurrentCulture; + + CultureInfo.CurrentCulture = Thread.CurrentThread.CurrentCulture = culture; + + try + { + assertions(); + } + finally + { + CultureInfo.CurrentCulture = Thread.CurrentThread.CurrentCulture = previousCulture; + } } } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/EntityManipulatorTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/EntityManipulatorTests.cs index b644cff..1a6b7f2 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/EntityManipulatorTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/EntityManipulatorTests.cs @@ -9,6 +9,15 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.DatabaseAdapters; public class EntityManipulatorTests : UnitTestsBase { + public static IEnumerable> GetManipulators() + { + yield return new(new MySqlEntityManipulator(new())); + yield return new(new OracleEntityManipulator(new())); + yield return new(new PostgreSqlEntityManipulator(new())); + yield return new(new SqliteEntityManipulator(new())); + yield return new(new SqlServerEntityManipulator(new())); + } + [Theory] [MemberData(nameof(GetManipulators))] public void ShouldGuardAgainstNullArguments(IEntityManipulator manipulator) @@ -64,13 +73,4 @@ public void ShouldGuardAgainstNullArguments(IEntityManipulator manipulator) manipulator.UpdateEntityAsync(this.MockDbConnection, entity, null, CancellationToken.None) ); } - - public static IEnumerable> GetManipulators() - { - yield return new(new MySqlEntityManipulator(new())); - yield return new(new OracleEntityManipulator(new())); - yield return new(new PostgreSqlEntityManipulator(new())); - yield return new(new SqliteEntityManipulator(new())); - yield return new(new SqlServerEntityManipulator(new())); - } } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlDatabaseAdapterTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlDatabaseAdapterTests.cs index 2291edd..a31edc3 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlDatabaseAdapterTests.cs @@ -4,6 +4,8 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.DatabaseAdapters.MySql; public class MySqlDatabaseAdapterTests : UnitTestsBase { + private readonly MySqlDatabaseAdapter adapter = new(); + [Fact] public void BindParameterValue_BytesValue_ShouldSetDbTypeAndValue() { @@ -177,6 +179,4 @@ public void TemporaryTableBuilder_ShouldReturnBuilder() => [Fact] public void WasSqlStatementCancelledByCancellationToken_ShouldAlwaysReturnFalse() => this.adapter.WasSqlStatementCancelledByCancellationToken(new(), CancellationToken.None).Should().BeFalse(); - - private readonly MySqlDatabaseAdapter adapter = new(); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlTemporaryTableBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlTemporaryTableBuilderTests.cs index 04a8d68..d6d1e97 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlTemporaryTableBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/MySql/MySqlTemporaryTableBuilderTests.cs @@ -4,17 +4,7 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.DatabaseAdapters.MySql; public class MySqlTemporaryTableBuilderTests : UnitTestsBase { - [Fact] - public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() - { - Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int))) - .Should() - .Throw(); - - Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int))) - .Should() - .Throw(); - } + private readonly MySqlTemporaryTableBuilder builder = new(new()); [Fact] public async Task BuildTemporaryTableAsync_NameIsNullOrEmptyOrWhitespace_ShouldThrow() @@ -32,6 +22,18 @@ await Invoking(() => .ThrowAsync(); } + [Fact] + public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() + { + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int))) + .Should() + .Throw(); + + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int))) + .Should() + .Throw(); + } + [Fact] public void ShouldGuardAgainstNullArguments() { @@ -45,6 +47,4 @@ public void ShouldGuardAgainstNullArguments() this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) ); } - - private readonly MySqlTemporaryTableBuilder builder = new(new()); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs index 7108ecf..4aee9ee 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleDatabaseAdapterTests.cs @@ -5,6 +5,8 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.DatabaseAdapters.Oracle; public class OracleDatabaseAdapterTests : UnitTestsBase { + private readonly OracleDatabaseAdapter adapter = new(); + [Fact] public void AllowTemporaryTables_ShouldReturnFalsePerDefault() => OracleDatabaseAdapter.AllowTemporaryTables.Should().BeFalse(); @@ -336,6 +338,4 @@ public void TemporaryTableBuilder_AllowTemporaryTablesIsTrue_ShouldReturnBuilder this.adapter.TemporaryTableBuilder.Should().BeOfType(); } - - private readonly OracleDatabaseAdapter adapter = new(); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleTemporaryTableBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleTemporaryTableBuilderTests.cs index 8227b60..c53c6de 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleTemporaryTableBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Oracle/OracleTemporaryTableBuilderTests.cs @@ -4,14 +4,18 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.DatabaseAdapters.Oracle; public class OracleTemporaryTableBuilderTests : UnitTestsBase { + private readonly OracleTemporaryTableBuilder builder = new(new()); + [Fact] - public void BuildTemporaryTable_AllowTemporaryTablesIsFalse_ShouldThrow() + public Task BuildTemporaryTableAsync_AllowTemporaryTablesIsFalse_ShouldThrow() { OracleDatabaseAdapter.AllowTemporaryTables = false; - Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int))) + return Invoking(() => + this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) + ) .Should() - .Throw() + .ThrowAsync() .WithMessage( "The temporary tables feature of DbConnectionPlus is currently disabled for Oracle databases. " + $"To enable it set {typeof(OracleDatabaseAdapter)}.AllowTemporaryTables to true, but be sure to " @@ -21,27 +25,29 @@ public void BuildTemporaryTable_AllowTemporaryTablesIsFalse_ShouldThrow() } [Fact] - public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() + public async Task BuildTemporaryTableAsync_NameIsNullOrEmptyOrWhitespace_ShouldThrow() { - Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int))) + await Invoking(() => + this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) + ) .Should() - .Throw(); + .ThrowAsync(); - Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int))) + await Invoking(() => + this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) + ) .Should() - .Throw(); + .ThrowAsync(); } [Fact] - public Task BuildTemporaryTableAsync_AllowTemporaryTablesIsFalse_ShouldThrow() + public void BuildTemporaryTable_AllowTemporaryTablesIsFalse_ShouldThrow() { OracleDatabaseAdapter.AllowTemporaryTables = false; - return Invoking(() => - this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) - ) + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int))) .Should() - .ThrowAsync() + .Throw() .WithMessage( "The temporary tables feature of DbConnectionPlus is currently disabled for Oracle databases. " + $"To enable it set {typeof(OracleDatabaseAdapter)}.AllowTemporaryTables to true, but be sure to " @@ -51,19 +57,15 @@ public Task BuildTemporaryTableAsync_AllowTemporaryTablesIsFalse_ShouldThrow() } [Fact] - public async Task BuildTemporaryTableAsync_NameIsNullOrEmptyOrWhitespace_ShouldThrow() + public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() { - await Invoking(() => - this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "", new[] { 1 }, typeof(int)) - ) + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int))) .Should() - .ThrowAsync(); + .Throw(); - await Invoking(() => - this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int)) - ) + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int))) .Should() - .ThrowAsync(); + .Throw(); } [Fact] @@ -79,6 +81,4 @@ public void ShouldGuardAgainstNullArguments() this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) ); } - - private readonly OracleTemporaryTableBuilder builder = new(new()); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlDatabaseAdapterTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlDatabaseAdapterTests.cs index 1da542a..44def57 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlDatabaseAdapterTests.cs @@ -5,6 +5,8 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.DatabaseAdapters.PostgreSql; public class PostgreSqlDatabaseAdapterTests : UnitTestsBase { + private readonly PostgreSqlDatabaseAdapter adapter = new(); + [Fact] public void BindParameterValue_BytesValue_ShouldSetDbTypeAndValue() { @@ -219,6 +221,4 @@ public void ShouldGuardAgainstNullArguments() [Fact] public void TemporaryTableBuilder_ShouldReturnBuilder() => this.adapter.TemporaryTableBuilder.Should().BeOfType(); - - private readonly PostgreSqlDatabaseAdapter adapter = new(); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlTemporaryTableBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlTemporaryTableBuilderTests.cs index fd73617..30d6e95 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlTemporaryTableBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/PostgreSql/PostgreSqlTemporaryTableBuilderTests.cs @@ -4,17 +4,7 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.DatabaseAdapters.PostgreSql; public class PostgreSqlTemporaryTableBuilderTests : UnitTestsBase { - [Fact] - public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() - { - Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int))) - .Should() - .Throw(); - - Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int))) - .Should() - .Throw(); - } + private readonly PostgreSqlTemporaryTableBuilder builder = new(new()); [Fact] public async Task BuildTemporaryTableAsync_NameIsNullOrEmptyOrWhitespace_ShouldThrow() @@ -32,6 +22,18 @@ await Invoking(() => .ThrowAsync(); } + [Fact] + public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() + { + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int))) + .Should() + .Throw(); + + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int))) + .Should() + .Throw(); + } + [Fact] public void ShouldGuardAgainstNullArguments() { @@ -45,6 +47,4 @@ public void ShouldGuardAgainstNullArguments() this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) ); } - - private readonly PostgreSqlTemporaryTableBuilder builder = new(new()); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerDatabaseAdapterTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerDatabaseAdapterTests.cs index a449ae6..3d982dd 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerDatabaseAdapterTests.cs @@ -4,6 +4,8 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.DatabaseAdapters.SqlServer; public class SqlServerDatabaseAdapterTests : UnitTestsBase { + private readonly SqlServerDatabaseAdapter adapter = new(); + [Fact] public void BindParameterValue_BytesValue_ShouldSetDbTypeAndValue() { @@ -176,6 +178,4 @@ public void ShouldGuardAgainstNullArguments() [Fact] public void TemporaryTableBuilder_ShouldReturnBuilder() => this.adapter.TemporaryTableBuilder.Should().BeOfType(); - - private readonly SqlServerDatabaseAdapter adapter = new(); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerTemporaryTableBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerTemporaryTableBuilderTests.cs index be73cd3..736e3b7 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerTemporaryTableBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/SqlServer/SqlServerTemporaryTableBuilderTests.cs @@ -4,17 +4,7 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.DatabaseAdapters.SqlServer; public class SqlServerTemporaryTableBuilderTests : UnitTestsBase { - [Fact] - public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() - { - Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int))) - .Should() - .Throw(); - - Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int))) - .Should() - .Throw(); - } + private readonly SqlServerTemporaryTableBuilder builder = new(new()); [Fact] public async Task BuildTemporaryTableAsync_NameIsNullOrEmptyOrWhitespace_ShouldThrow() @@ -32,6 +22,18 @@ await Invoking(() => .ThrowAsync(); } + [Fact] + public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() + { + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int))) + .Should() + .Throw(); + + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int))) + .Should() + .Throw(); + } + [Fact] public void ShouldGuardAgainstNullArguments() { @@ -45,6 +47,4 @@ public void ShouldGuardAgainstNullArguments() this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) ); } - - private readonly SqlServerTemporaryTableBuilder builder = new(new()); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteDatabaseAdapterTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteDatabaseAdapterTests.cs index 0fc96a1..d734903 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteDatabaseAdapterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteDatabaseAdapterTests.cs @@ -4,6 +4,8 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.DatabaseAdapters.Sqlite; public class SqliteDatabaseAdapterTests : UnitTestsBase { + private readonly SqliteDatabaseAdapter adapter = new(); + [Fact] public void BindParameterValue_BytesValue_ShouldSetDbTypeAndValue() { @@ -179,6 +181,4 @@ public void TemporaryTableBuilder_ShouldReturnBuilder() => [Fact] public void WasSqlStatementCancelledByCancellationToken_ShouldAlwaysReturnFalse() => this.adapter.WasSqlStatementCancelledByCancellationToken(new(), CancellationToken.None).Should().BeFalse(); - - private readonly SqliteDatabaseAdapter adapter = new(); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteTemporaryTableBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteTemporaryTableBuilderTests.cs index 7e57b9c..fef8d45 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteTemporaryTableBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/Sqlite/SqliteTemporaryTableBuilderTests.cs @@ -4,17 +4,7 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.DatabaseAdapters.Sqlite; public class SqliteTemporaryTableBuilderTests : UnitTestsBase { - [Fact] - public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() - { - Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int))) - .Should() - .Throw(); - - Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int))) - .Should() - .Throw(); - } + private readonly SqliteTemporaryTableBuilder builder = new(new()); [Fact] public async Task BuildTemporaryTableAsync_NameIsNullOrEmptyOrWhitespace_ShouldThrow() @@ -32,6 +22,18 @@ await Invoking(() => .ThrowAsync(); } + [Fact] + public void BuildTemporaryTable_NameIsNullOrEmptyOrWhitespace_ShouldThrow() + { + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, "", new[] { 1 }, typeof(int))) + .Should() + .Throw(); + + Invoking(() => this.builder.BuildTemporaryTable(this.MockDbConnection, null, " ", new[] { 1 }, typeof(int))) + .Should() + .Throw(); + } + [Fact] public void ShouldGuardAgainstNullArguments() { @@ -45,6 +47,4 @@ public void ShouldGuardAgainstNullArguments() this.builder.BuildTemporaryTableAsync(this.MockDbConnection, null, "Name", new[] { 1 }, typeof(int)) ); } - - private readonly SqliteTemporaryTableBuilder builder = new(new()); } diff --git a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/TemporaryTableDisposerTests.cs b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/TemporaryTableDisposerTests.cs index 16de010..6363efc 100644 --- a/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/TemporaryTableDisposerTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DatabaseAdapters/TemporaryTableDisposerTests.cs @@ -5,58 +5,58 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.DatabaseAdapters; public class TemporaryTableDisposerTests : UnitTestsBase { [Fact] - public void Dispose_AlreadyDisposed_ShouldNotCallDropFunctionAgain() + public async Task DisposeAsync_AlreadyDisposed_ShouldNotCallAsyncDropFunctionAgain() { var dropTableFunction = Substitute.For(); var dropTableAsyncFunction = Substitute.For>(); var disposer = new TemporaryTableDisposer(dropTableFunction, dropTableAsyncFunction); - disposer.Dispose(); - disposer.Dispose(); - disposer.Dispose(); + await disposer.DisposeAsync(); + await disposer.DisposeAsync(); + await disposer.DisposeAsync(); - dropTableFunction.Received(1).Invoke(); + await dropTableAsyncFunction.Received(1).Invoke(); } [Fact] - public void Dispose_ShouldCallDropFunction() + public async Task DisposeAsync_ShouldCallAsyncDropFunction() { var dropTableFunction = Substitute.For(); var dropTableAsyncFunction = Substitute.For>(); var disposer = new TemporaryTableDisposer(dropTableFunction, dropTableAsyncFunction); - disposer.Dispose(); - dropTableFunction.Received(1).Invoke(); + await disposer.DisposeAsync(); + + await dropTableAsyncFunction.Received(1).Invoke(); } [Fact] - public async Task DisposeAsync_AlreadyDisposed_ShouldNotCallAsyncDropFunctionAgain() + public void Dispose_AlreadyDisposed_ShouldNotCallDropFunctionAgain() { var dropTableFunction = Substitute.For(); var dropTableAsyncFunction = Substitute.For>(); var disposer = new TemporaryTableDisposer(dropTableFunction, dropTableAsyncFunction); - await disposer.DisposeAsync(); - await disposer.DisposeAsync(); - await disposer.DisposeAsync(); + disposer.Dispose(); + disposer.Dispose(); + disposer.Dispose(); - await dropTableAsyncFunction.Received(1).Invoke(); + dropTableFunction.Received(1).Invoke(); } [Fact] - public async Task DisposeAsync_ShouldCallAsyncDropFunction() + public void Dispose_ShouldCallDropFunction() { var dropTableFunction = Substitute.For(); var dropTableAsyncFunction = Substitute.For>(); var disposer = new TemporaryTableDisposer(dropTableFunction, dropTableAsyncFunction); + disposer.Dispose(); - await disposer.DisposeAsync(); - - await dropTableAsyncFunction.Received(1).Invoke(); + dropTableFunction.Received(1).Invoke(); } [Fact] diff --git a/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandBuilderTests.cs b/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandBuilderTests.cs index f3355b3..fc45de3 100644 --- a/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandBuilderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandBuilderTests.cs @@ -9,6 +9,9 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.DbCommands; public class DbCommandBuilderTests : UnitTestsBase { + private readonly List testEntityIds = Generate.Ids(); + private readonly long testProductId = Generate.Id(); + [Theory] [InlineData(false)] [InlineData(true)] @@ -644,7 +647,4 @@ public async Task BuildDbCommand_Transaction_ShouldUseTransaction(bool useAsyncA return Task.FromException<(DbCommand, DbCommandDisposer)>(ex); } } - - private readonly List testEntityIds = Generate.Ids(); - private readonly long testProductId = Generate.Id(); } diff --git a/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandDisposerTests.cs b/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandDisposerTests.cs index f191f30..424374c 100644 --- a/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandDisposerTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbCommands/DbCommandDisposerTests.cs @@ -8,7 +8,7 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.DbCommands; public class DbCommandDisposerTests : UnitTestsBase { [Fact] - public void Dispose_AlreadyDisposed_ShouldNotDisposeCommandResourcesAgain() + public async Task DisposeAsync_AlreadyDisposed_ShouldNotDisposeCommandResourcesAsyncAgain() { using var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; @@ -35,17 +35,17 @@ public void Dispose_AlreadyDisposed_ShouldNotDisposeCommandResourcesAgain() cancellationTokenRegistration ); - disposer.Dispose(); - disposer.Dispose(); - disposer.Dispose(); + await disposer.DisposeAsync(); + await disposer.DisposeAsync(); + await disposer.DisposeAsync(); - this.MockDbCommand.Received(1).Dispose(); - dropTableFunction1.Received(1).Invoke(); - dropTableFunction2.Received(1).Invoke(); + await this.MockDbCommand.Received(1).DisposeAsync(); + await dropTableAsyncFunction1.Received(1).Invoke(); + await dropTableAsyncFunction2.Received(1).Invoke(); } [Fact] - public void Dispose_ShouldDisposeCommandResources() + public async Task DisposeAsync_ShouldDisposeCommandResourcesAsync() { using var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; @@ -72,19 +72,19 @@ public void Dispose_ShouldDisposeCommandResources() cancellationTokenRegistration ); - disposer.Dispose(); + await disposer.DisposeAsync(); - this.MockDbCommand.Received(1).Dispose(); - dropTableFunction1.Received(1).Invoke(); - dropTableFunction2.Received(1).Invoke(); + await this.MockDbCommand.Received(1).DisposeAsync(); + await dropTableAsyncFunction1.Received(1).Invoke(); + await dropTableAsyncFunction2.Received(1).Invoke(); // Verify that cancellation token registration is disposed. - cancellationTokenSource.Cancel(); + await cancellationTokenSource.CancelAsync(); this.MockDbCommand.DidNotReceive().Cancel(); } [Fact] - public async Task DisposeAsync_AlreadyDisposed_ShouldNotDisposeCommandResourcesAsyncAgain() + public void Dispose_AlreadyDisposed_ShouldNotDisposeCommandResourcesAgain() { using var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; @@ -111,17 +111,17 @@ public async Task DisposeAsync_AlreadyDisposed_ShouldNotDisposeCommandResourcesA cancellationTokenRegistration ); - await disposer.DisposeAsync(); - await disposer.DisposeAsync(); - await disposer.DisposeAsync(); + disposer.Dispose(); + disposer.Dispose(); + disposer.Dispose(); - await this.MockDbCommand.Received(1).DisposeAsync(); - await dropTableAsyncFunction1.Received(1).Invoke(); - await dropTableAsyncFunction2.Received(1).Invoke(); + this.MockDbCommand.Received(1).Dispose(); + dropTableFunction1.Received(1).Invoke(); + dropTableFunction2.Received(1).Invoke(); } [Fact] - public async Task DisposeAsync_ShouldDisposeCommandResourcesAsync() + public void Dispose_ShouldDisposeCommandResources() { using var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; @@ -148,14 +148,14 @@ public async Task DisposeAsync_ShouldDisposeCommandResourcesAsync() cancellationTokenRegistration ); - await disposer.DisposeAsync(); + disposer.Dispose(); - await this.MockDbCommand.Received(1).DisposeAsync(); - await dropTableAsyncFunction1.Received(1).Invoke(); - await dropTableAsyncFunction2.Received(1).Invoke(); + this.MockDbCommand.Received(1).Dispose(); + dropTableFunction1.Received(1).Invoke(); + dropTableFunction2.Received(1).Invoke(); // Verify that cancellation token registration is disposed. - await cancellationTokenSource.CancelAsync(); + cancellationTokenSource.Cancel(); this.MockDbCommand.DidNotReceive().Cancel(); } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.DeleteEntitiesTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.DeleteEntitiesTests.cs index 67a2171..899b180 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.DeleteEntitiesTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.DeleteEntitiesTests.cs @@ -3,42 +3,42 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; public class DbConnectionExtensions_DeleteEntitiesTests : UnitTestsBase { [Fact] - public void DeleteEntities_ShouldCallEntityManipulator() + public async Task DeleteEntitiesAsync_ShouldCallEntityManipulator() { var entities = Generate.Multiple(); - using var transaction = this.MockDbConnection.BeginTransaction(); + await using var transaction = await this.MockDbConnection.BeginTransactionAsync(); var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.DeleteEntities(this.MockDbConnection, entities, transaction, cancellationToken) + this.MockEntityManipulator.DeleteEntitiesAsync(this.MockDbConnection, entities, transaction, cancellationToken) .Returns(numberOfAffectedRows); - this.MockDbConnection.DeleteEntities(entities, transaction, cancellationToken) + (await this.MockDbConnection.DeleteEntitiesAsync(entities, transaction, cancellationToken)) .Should() .Be(numberOfAffectedRows); - this.MockEntityManipulator.Received() - .DeleteEntities(this.MockDbConnection, entities, transaction, cancellationToken); + await this + .MockEntityManipulator.Received() + .DeleteEntitiesAsync(this.MockDbConnection, entities, transaction, cancellationToken); } [Fact] - public async Task DeleteEntitiesAsync_ShouldCallEntityManipulator() + public void DeleteEntities_ShouldCallEntityManipulator() { var entities = Generate.Multiple(); - await using var transaction = await this.MockDbConnection.BeginTransactionAsync(); + using var transaction = this.MockDbConnection.BeginTransaction(); var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.DeleteEntitiesAsync(this.MockDbConnection, entities, transaction, cancellationToken) + this.MockEntityManipulator.DeleteEntities(this.MockDbConnection, entities, transaction, cancellationToken) .Returns(numberOfAffectedRows); - (await this.MockDbConnection.DeleteEntitiesAsync(entities, transaction, cancellationToken)) + this.MockDbConnection.DeleteEntities(entities, transaction, cancellationToken) .Should() .Be(numberOfAffectedRows); - await this - .MockEntityManipulator.Received() - .DeleteEntitiesAsync(this.MockDbConnection, entities, transaction, cancellationToken); + this.MockEntityManipulator.Received() + .DeleteEntities(this.MockDbConnection, entities, transaction, cancellationToken); } [Fact] diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.DeleteEntityTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.DeleteEntityTests.cs index 94ba8ea..2ce4383 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.DeleteEntityTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.DeleteEntityTests.cs @@ -3,40 +3,40 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; public class DbConnectionExtensions_DeleteEntityTests : UnitTestsBase { [Fact] - public void DeleteEntity_ShouldCallEntityManipulator() + public async Task DeleteEntityAsync_ShouldCallEntityManipulator() { var entity = Generate.Single(); - using var transaction = this.MockDbConnection.BeginTransaction(); + await using var transaction = await this.MockDbConnection.BeginTransactionAsync(); var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.DeleteEntity(this.MockDbConnection, entity, transaction, cancellationToken) + this.MockEntityManipulator.DeleteEntityAsync(this.MockDbConnection, entity, transaction, cancellationToken) .Returns(numberOfAffectedRows); - this.MockDbConnection.DeleteEntity(entity, transaction, cancellationToken).Should().Be(numberOfAffectedRows); + (await this.MockDbConnection.DeleteEntityAsync(entity, transaction, cancellationToken)) + .Should() + .Be(numberOfAffectedRows); - this.MockEntityManipulator.Received() - .DeleteEntity(this.MockDbConnection, entity, transaction, cancellationToken); + await this + .MockEntityManipulator.Received() + .DeleteEntityAsync(this.MockDbConnection, entity, transaction, cancellationToken); } [Fact] - public async Task DeleteEntityAsync_ShouldCallEntityManipulator() + public void DeleteEntity_ShouldCallEntityManipulator() { var entity = Generate.Single(); - await using var transaction = await this.MockDbConnection.BeginTransactionAsync(); + using var transaction = this.MockDbConnection.BeginTransaction(); var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.DeleteEntityAsync(this.MockDbConnection, entity, transaction, cancellationToken) + this.MockEntityManipulator.DeleteEntity(this.MockDbConnection, entity, transaction, cancellationToken) .Returns(numberOfAffectedRows); - (await this.MockDbConnection.DeleteEntityAsync(entity, transaction, cancellationToken)) - .Should() - .Be(numberOfAffectedRows); + this.MockDbConnection.DeleteEntity(entity, transaction, cancellationToken).Should().Be(numberOfAffectedRows); - await this - .MockEntityManipulator.Received() - .DeleteEntityAsync(this.MockDbConnection, entity, transaction, cancellationToken); + this.MockEntityManipulator.Received() + .DeleteEntity(this.MockDbConnection, entity, transaction, cancellationToken); } [Fact] diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.InsertEntitiesTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.InsertEntitiesTests.cs index c7f1ff5..c460b1a 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.InsertEntitiesTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.InsertEntitiesTests.cs @@ -3,42 +3,42 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; public class DbConnectionExtensions_InsertEntitiesTests : UnitTestsBase { [Fact] - public void InsertEntities_ShouldCallEntityManipulator() + public async Task InsertEntitiesAsync_ShouldCallEntityManipulator() { var entities = Generate.Multiple(); - using var transaction = this.MockDbConnection.BeginTransaction(); + await using var transaction = await this.MockDbConnection.BeginTransactionAsync(); var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.InsertEntities(this.MockDbConnection, entities, transaction, cancellationToken) + this.MockEntityManipulator.InsertEntitiesAsync(this.MockDbConnection, entities, transaction, cancellationToken) .Returns(numberOfAffectedRows); - this.MockDbConnection.InsertEntities(entities, transaction, cancellationToken) + (await this.MockDbConnection.InsertEntitiesAsync(entities, transaction, cancellationToken)) .Should() .Be(numberOfAffectedRows); - this.MockEntityManipulator.Received() - .InsertEntities(this.MockDbConnection, entities, transaction, cancellationToken); + await this + .MockEntityManipulator.Received() + .InsertEntitiesAsync(this.MockDbConnection, entities, transaction, cancellationToken); } [Fact] - public async Task InsertEntitiesAsync_ShouldCallEntityManipulator() + public void InsertEntities_ShouldCallEntityManipulator() { var entities = Generate.Multiple(); - await using var transaction = await this.MockDbConnection.BeginTransactionAsync(); + using var transaction = this.MockDbConnection.BeginTransaction(); var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.InsertEntitiesAsync(this.MockDbConnection, entities, transaction, cancellationToken) + this.MockEntityManipulator.InsertEntities(this.MockDbConnection, entities, transaction, cancellationToken) .Returns(numberOfAffectedRows); - (await this.MockDbConnection.InsertEntitiesAsync(entities, transaction, cancellationToken)) + this.MockDbConnection.InsertEntities(entities, transaction, cancellationToken) .Should() .Be(numberOfAffectedRows); - await this - .MockEntityManipulator.Received() - .InsertEntitiesAsync(this.MockDbConnection, entities, transaction, cancellationToken); + this.MockEntityManipulator.Received() + .InsertEntities(this.MockDbConnection, entities, transaction, cancellationToken); } [Fact] diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.InsertEntityTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.InsertEntityTests.cs index 682dd5f..131e494 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.InsertEntityTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.InsertEntityTests.cs @@ -3,40 +3,40 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; public class DbConnectionExtensions_InsertEntityTests : UnitTestsBase { [Fact] - public void InsertEntity_ShouldCallEntityManipulator() + public async Task InsertEntityAsync_ShouldCallEntityManipulator() { var entity = Generate.Single(); - using var transaction = this.MockDbConnection.BeginTransaction(); + await using var transaction = await this.MockDbConnection.BeginTransactionAsync(); var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.InsertEntity(this.MockDbConnection, entity, transaction, cancellationToken) + this.MockEntityManipulator.InsertEntityAsync(this.MockDbConnection, entity, transaction, cancellationToken) .Returns(numberOfAffectedRows); - this.MockDbConnection.InsertEntity(entity, transaction, cancellationToken).Should().Be(numberOfAffectedRows); + (await this.MockDbConnection.InsertEntityAsync(entity, transaction, cancellationToken)) + .Should() + .Be(numberOfAffectedRows); - this.MockEntityManipulator.Received() - .InsertEntity(this.MockDbConnection, entity, transaction, cancellationToken); + await this + .MockEntityManipulator.Received() + .InsertEntityAsync(this.MockDbConnection, entity, transaction, cancellationToken); } [Fact] - public async Task InsertEntityAsync_ShouldCallEntityManipulator() + public void InsertEntity_ShouldCallEntityManipulator() { var entity = Generate.Single(); - await using var transaction = await this.MockDbConnection.BeginTransactionAsync(); + using var transaction = this.MockDbConnection.BeginTransaction(); var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.InsertEntityAsync(this.MockDbConnection, entity, transaction, cancellationToken) + this.MockEntityManipulator.InsertEntity(this.MockDbConnection, entity, transaction, cancellationToken) .Returns(numberOfAffectedRows); - (await this.MockDbConnection.InsertEntityAsync(entity, transaction, cancellationToken)) - .Should() - .Be(numberOfAffectedRows); + this.MockDbConnection.InsertEntity(entity, transaction, cancellationToken).Should().Be(numberOfAffectedRows); - await this - .MockEntityManipulator.Received() - .InsertEntityAsync(this.MockDbConnection, entity, transaction, cancellationToken); + this.MockEntityManipulator.Received() + .InsertEntity(this.MockDbConnection, entity, transaction, cancellationToken); } [Fact] diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ParameterTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ParameterTests.cs index 6c6c284..8616e96 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ParameterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.ParameterTests.cs @@ -4,6 +4,8 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; public class DbConnectionExtensions_ParameterTests : UnitTestsBase { + private const long TestProductId = 106L; + [Fact] public void Parameter_ShouldInferParameterNameFromValueExpressionIfPossible() { @@ -50,6 +52,4 @@ public void Parameter_ShouldTruncateInferredParameterName() .HaveLength(60) .And.Be("Longname_1234567890_1234567890_1234567890_1234567890_1234567"); } - - private const long TestProductId = 106L; } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.TemporaryTableTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.TemporaryTableTests.cs index a2f5d76..de6df49 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.TemporaryTableTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.TemporaryTableTests.cs @@ -4,6 +4,8 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests; public class DbConnectionExtensions_TemporaryTableTests : UnitTestsBase { + private readonly List testEntityIds = Generate.Ids(); + [Fact] public void ShouldGuardAgainstNullArguments() => ArgumentNullGuardVerifier.Verify(() => TemporaryTable(new List())); @@ -71,6 +73,4 @@ public void TemporaryTable_TIsObject_ShouldThrow() => .Should() .Throw() .WithMessage($"The type parameter T cannot be the type {typeof(object)}."); - - private readonly List testEntityIds = Generate.Ids(); } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.UpdateEntitiesTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.UpdateEntitiesTests.cs index 63b3b7b..deae9d6 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.UpdateEntitiesTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.UpdateEntitiesTests.cs @@ -13,41 +13,41 @@ public void ShouldGuardAgainstNullArguments() } [Fact] - public void UpdateEntities_ShouldCallEntityManipulator() + public async Task UpdateEntitiesAsync_ShouldCallEntityManipulator() { var entities = Generate.Multiple(); - using var transaction = this.MockDbConnection.BeginTransaction(); + await using var transaction = await this.MockDbConnection.BeginTransactionAsync(); var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.UpdateEntities(this.MockDbConnection, entities, transaction, cancellationToken) + this.MockEntityManipulator.UpdateEntitiesAsync(this.MockDbConnection, entities, transaction, cancellationToken) .Returns(numberOfAffectedRows); - this.MockDbConnection.UpdateEntities(entities, transaction, cancellationToken) + (await this.MockDbConnection.UpdateEntitiesAsync(entities, transaction, cancellationToken)) .Should() .Be(numberOfAffectedRows); - this.MockEntityManipulator.Received() - .UpdateEntities(this.MockDbConnection, entities, transaction, cancellationToken); + await this + .MockEntityManipulator.Received() + .UpdateEntitiesAsync(this.MockDbConnection, entities, transaction, cancellationToken); } [Fact] - public async Task UpdateEntitiesAsync_ShouldCallEntityManipulator() + public void UpdateEntities_ShouldCallEntityManipulator() { var entities = Generate.Multiple(); - await using var transaction = await this.MockDbConnection.BeginTransactionAsync(); + using var transaction = this.MockDbConnection.BeginTransaction(); var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.UpdateEntitiesAsync(this.MockDbConnection, entities, transaction, cancellationToken) + this.MockEntityManipulator.UpdateEntities(this.MockDbConnection, entities, transaction, cancellationToken) .Returns(numberOfAffectedRows); - (await this.MockDbConnection.UpdateEntitiesAsync(entities, transaction, cancellationToken)) + this.MockDbConnection.UpdateEntities(entities, transaction, cancellationToken) .Should() .Be(numberOfAffectedRows); - await this - .MockEntityManipulator.Received() - .UpdateEntitiesAsync(this.MockDbConnection, entities, transaction, cancellationToken); + this.MockEntityManipulator.Received() + .UpdateEntities(this.MockDbConnection, entities, transaction, cancellationToken); } } diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.UpdateEntityTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.UpdateEntityTests.cs index 344fff1..b58dc9b 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.UpdateEntityTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.UpdateEntityTests.cs @@ -13,39 +13,39 @@ public void ShouldGuardAgainstNullArguments() } [Fact] - public void UpdateEntity_ShouldCallEntityManipulator() + public async Task UpdateEntityAsync_ShouldCallEntityManipulator() { var entity = Generate.Single(); - using var transaction = this.MockDbConnection.BeginTransaction(); + await using var transaction = await this.MockDbConnection.BeginTransactionAsync(); var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.UpdateEntity(this.MockDbConnection, entity, transaction, cancellationToken) + this.MockEntityManipulator.UpdateEntityAsync(this.MockDbConnection, entity, transaction, cancellationToken) .Returns(numberOfAffectedRows); - this.MockDbConnection.UpdateEntity(entity, transaction, cancellationToken).Should().Be(numberOfAffectedRows); + (await this.MockDbConnection.UpdateEntityAsync(entity, transaction, cancellationToken)) + .Should() + .Be(numberOfAffectedRows); - this.MockEntityManipulator.Received() - .UpdateEntity(this.MockDbConnection, entity, transaction, cancellationToken); + await this + .MockEntityManipulator.Received() + .UpdateEntityAsync(this.MockDbConnection, entity, transaction, cancellationToken); } [Fact] - public async Task UpdateEntityAsync_ShouldCallEntityManipulator() + public void UpdateEntity_ShouldCallEntityManipulator() { var entity = Generate.Single(); - await using var transaction = await this.MockDbConnection.BeginTransactionAsync(); + using var transaction = this.MockDbConnection.BeginTransaction(); var cancellationToken = TestContext.Current.CancellationToken; var numberOfAffectedRows = Generate.SmallNumber(); - this.MockEntityManipulator.UpdateEntityAsync(this.MockDbConnection, entity, transaction, cancellationToken) + this.MockEntityManipulator.UpdateEntity(this.MockDbConnection, entity, transaction, cancellationToken) .Returns(numberOfAffectedRows); - (await this.MockDbConnection.UpdateEntityAsync(entity, transaction, cancellationToken)) - .Should() - .Be(numberOfAffectedRows); + this.MockDbConnection.UpdateEntity(entity, transaction, cancellationToken).Should().Be(numberOfAffectedRows); - await this - .MockEntityManipulator.Received() - .UpdateEntityAsync(this.MockDbConnection, entity, transaction, cancellationToken); + this.MockEntityManipulator.Received() + .UpdateEntity(this.MockDbConnection, entity, transaction, cancellationToken); } } diff --git a/tests/DbConnectionPlus.UnitTests/Dynamic/DataRowTests.cs b/tests/DbConnectionPlus.UnitTests/Dynamic/DataRowTests.cs index 1795b3f..f99fcca 100644 --- a/tests/DbConnectionPlus.UnitTests/Dynamic/DataRowTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Dynamic/DataRowTests.cs @@ -9,40 +9,6 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.Dynamic; public class DataRowTests : UnitTestsBase { - [Fact] - public void ShouldBeMutable() - { - var dictionary = new Dictionary - { - { "ColumnA", Generate.ScalarValue() }, - { "ColumnB", Generate.ScalarValue() }, - { "ColumnC", Generate.ScalarValue() }, - }; - - var dataRow = new DataRow(dictionary); - - dataRow["ColumnA"].Should().Be(dictionary["ColumnA"]); - - dataRow["ColumnB"].Should().Be(dictionary["ColumnB"]); - - dataRow["ColumnC"].Should().Be(dictionary["ColumnC"]); - - var newValueA = Generate.ScalarValue(); - dataRow["ColumnA"] = newValueA; - - dataRow["ColumnA"].Should().Be(newValueA); - - var newValueB = Generate.ScalarValue(); - dataRow["ColumnB"] = newValueB; - - dataRow["ColumnB"].Should().Be(newValueB); - - var newValueC = Generate.ScalarValue(); - dataRow["ColumnC"] = newValueC; - - dataRow["ColumnC"].Should().Be(newValueC); - } - [Fact] public void ShouldAllowDynamicMemberAccess() { @@ -88,50 +54,37 @@ public void ShouldAllowDynamicMemberAssignmentOfUnknownColumn() } [Fact] - public void ShouldProvideDynamicMemberNames() + public void ShouldBeMutable() { var dictionary = new Dictionary { { "ColumnA", Generate.ScalarValue() }, { "ColumnB", Generate.ScalarValue() }, + { "ColumnC", Generate.ScalarValue() }, }; - IDynamicMetaObjectProvider dataRow = new DataRow(dictionary); - - var metaObject = dataRow.GetMetaObject(Expression.Constant(dataRow)); - - metaObject.GetDynamicMemberNames().Should().BeEquivalentTo("ColumnA", "ColumnB"); - } + var dataRow = new DataRow(dictionary); - [Fact] - public void ShouldThrowWhenDynamicallyReadingUnknownColumn() - { - dynamic dataRow = new DataRow(new Dictionary()); + dataRow["ColumnA"].Should().Be(dictionary["ColumnA"]); - Invoking(() => (object?)dataRow.UnknownColumn).Should().Throw(); - } + dataRow["ColumnB"].Should().Be(dictionary["ColumnB"]); - [Fact] - public void ShouldResolveDynamicPropertyAccessToColumnsAndNotToOwnProperties() - { - dynamic dataRow = new DataRow(new Dictionary { { "ColumnA", Generate.ScalarValue() } }); + dataRow["ColumnC"].Should().Be(dictionary["ColumnC"]); - // "Count" is a property of DataRow, but through a dynamic reference it addresses a column of that name. - Invoking(() => (object?)dataRow.Count).Should().Throw(); + var newValueA = Generate.ScalarValue(); + dataRow["ColumnA"] = newValueA; - dynamic rowWithShadowingColumn = new DataRow(new Dictionary { { "Count", 42 } }); + dataRow["ColumnA"].Should().Be(newValueA); - ((object?)rowWithShadowingColumn.Count).Should().Be(42); - } + var newValueB = Generate.ScalarValue(); + dataRow["ColumnB"] = newValueB; - [Fact] - public void ShouldResolveDynamicMethodCallsToOwnMembers() - { - dynamic dataRow = new DataRow(new Dictionary { { "ColumnA", Generate.ScalarValue() } }); + dataRow["ColumnB"].Should().Be(newValueB); - ((bool)dataRow.ContainsKey("ColumnA")).Should().BeTrue(); + var newValueC = Generate.ScalarValue(); + dataRow["ColumnC"] = newValueC; - ((bool)dataRow.ContainsKey("ColumnB")).Should().BeFalse(); + dataRow["ColumnC"].Should().Be(newValueC); } [Fact] @@ -149,6 +102,22 @@ public void ShouldForwardAllMethodCallsToDictionary() DecoratorAssertions.AssertDecoratorForwardsAllCalls(fixture, dataRow, dictionary, exceptions); } + [Fact] + public void ShouldProvideDynamicMemberNames() + { + var dictionary = new Dictionary + { + { "ColumnA", Generate.ScalarValue() }, + { "ColumnB", Generate.ScalarValue() }, + }; + + IDynamicMetaObjectProvider dataRow = new DataRow(dictionary); + + var metaObject = dataRow.GetMetaObject(Expression.Constant(dataRow)); + + metaObject.GetDynamicMemberNames().Should().BeEquivalentTo("ColumnA", "ColumnB"); + } + [Fact] public void ShouldProvideRowData() { @@ -168,6 +137,37 @@ public void ShouldProvideRowData() dataRow["ColumnC"].Should().Be(dictionary["ColumnC"]); } + [Fact] + public void ShouldResolveDynamicMethodCallsToOwnMembers() + { + dynamic dataRow = new DataRow(new Dictionary { { "ColumnA", Generate.ScalarValue() } }); + + ((bool)dataRow.ContainsKey("ColumnA")).Should().BeTrue(); + + ((bool)dataRow.ContainsKey("ColumnB")).Should().BeFalse(); + } + + [Fact] + public void ShouldResolveDynamicPropertyAccessToColumnsAndNotToOwnProperties() + { + dynamic dataRow = new DataRow(new Dictionary { { "ColumnA", Generate.ScalarValue() } }); + + // "Count" is a property of DataRow, but through a dynamic reference it addresses a column of that name. + Invoking(() => (object?)dataRow.Count).Should().Throw(); + + dynamic rowWithShadowingColumn = new DataRow(new Dictionary { { "Count", 42 } }); + + ((object?)rowWithShadowingColumn.Count).Should().Be(42); + } + + [Fact] + public void ShouldThrowWhenDynamicallyReadingUnknownColumn() + { + dynamic dataRow = new DataRow(new Dictionary()); + + Invoking(() => (object?)dataRow.UnknownColumn).Should().Throw(); + } + [Fact] public void TryGetValue_ShouldForwardCallToDictionary() { diff --git a/tests/DbConnectionPlus.UnitTests/Entities/EntityHelperTests.cs b/tests/DbConnectionPlus.UnitTests/Entities/EntityHelperTests.cs index a95b4d9..55e1481 100644 --- a/tests/DbConnectionPlus.UnitTests/Entities/EntityHelperTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Entities/EntityHelperTests.cs @@ -8,6 +8,15 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.Entities; public class EntityHelperTests : UnitTestsBase { + /// + /// The method. + /// + private static readonly MethodInfo specimenFactoryCreateMethod = typeof(SpecimenFactory).GetMethod( + nameof(SpecimenFactory.Create), + BindingFlags.Public | BindingFlags.Static, + [typeof(ISpecimenBuilder)] + )!; + [Fact] public void FindCompatibleConstructor_MatchingPrivateConstructor_ShouldReturnPrivateConstructor() { @@ -52,6 +61,23 @@ public void FindCompatibleConstructor_NamesDoNotMatch_TypesMatch_ShouldReturnNul .Should() .BeNull(); + [Fact] + public void FindCompatibleConstructor_NamesMatchWithDifferentCasing_TypesMatch_ShouldReturnConstructor() + { + var constructor = EntityHelper.FindCompatibleConstructor( + typeof(ItemWithConstructor), + [("A", typeof(short)), ("B", typeof(int)), ("C", typeof(long))] + ); + + constructor.Should().NotBeNull(); + + constructor + .GetParameters() + .Select(a => a.ParameterType) + .Should() + .BeEquivalentTo([typeof(short), typeof(int), typeof(long)]); + } + [Fact] public void FindCompatibleConstructor_NamesMatch_TypesAreCompatible_ShouldReturnConstructor() { @@ -96,23 +122,6 @@ public void FindCompatibleConstructor_NamesMatch_TypesMatch_ShouldReturnConstruc .BeEquivalentTo([("a", typeof(short)), ("b", typeof(int)), ("c", typeof(long))]); } - [Fact] - public void FindCompatibleConstructor_NamesMatchWithDifferentCasing_TypesMatch_ShouldReturnConstructor() - { - var constructor = EntityHelper.FindCompatibleConstructor( - typeof(ItemWithConstructor), - [("A", typeof(short)), ("B", typeof(int)), ("C", typeof(long))] - ); - - constructor.Should().NotBeNull(); - - constructor - .GetParameters() - .Select(a => a.ParameterType) - .Should() - .BeEquivalentTo([typeof(short), typeof(int), typeof(long)]); - } - [Fact] public void FindCompatibleConstructor_NoMatchingConstructor_ShouldReturnNull() => EntityHelper @@ -418,43 +427,6 @@ public void GetEntityTypeMetadata_MoreThanOneIdentityProperty_ShouldThrow() => + "property per entity type." ); - [Fact] - public void ShouldGuardAgainstNullArguments() - { - (string Name, Type Type)[] constructorParameters = - [ - ("a", typeof(short)), - ("b", typeof(int)), - ("c", typeof(long)), - ]; - - ArgumentNullGuardVerifier.Verify(() => - EntityHelper.FindCompatibleConstructor(typeof(ItemWithConstructor), constructorParameters) - ); - ArgumentNullGuardVerifier.Verify(() => EntityHelper.FindParameterlessConstructor(typeof(ItemWithConstructor))); - ArgumentNullGuardVerifier.Verify(() => EntityHelper.GetEntityTypeMetadata(typeof(Entity))); - } - - [Fact] - public void GetEntityTypeMetadata_ShouldNotInvokePropertyAccessorsWhileCreatingMetadata() - { - // Every accessor of this entity throws, so building its metadata would fail if the accessors were - // resolved and invoked eagerly. - var metadata = EntityHelper.GetEntityTypeMetadata(typeof(EntityWithThrowingAccessors)); - - var property = metadata.MappedProperties.Single(p => - p.PropertyName == nameof(EntityWithThrowingAccessors.Value) - ); - - property.PropertyGetter.Should().NotBeNull(); - - // The accessor is real - it simply had not been called yet. - Invoking(() => property.PropertyGetter!(new EntityWithThrowingAccessors())) - .Should() - .Throw() - .WithMessage("Getter was invoked."); - } - [Fact] public void GetEntityTypeMetadata_PropertyAccessors_ShouldWorkAcrossRepeatedCalls() { @@ -495,25 +467,41 @@ public void GetEntityTypeMetadata_ShouldCreateAccessorsForNonPublicAndInitOnlySe entity.Name.Should().Be("Ada"); } - /// - /// The method. - /// - private static readonly MethodInfo specimenFactoryCreateMethod = typeof(SpecimenFactory).GetMethod( - nameof(SpecimenFactory.Create), - BindingFlags.Public | BindingFlags.Static, - [typeof(ISpecimenBuilder)] - )!; + [Fact] + public void GetEntityTypeMetadata_ShouldNotInvokePropertyAccessorsWhileCreatingMetadata() + { + // Every accessor of this entity throws, so building its metadata would fail if the accessors were + // resolved and invoked eagerly. + var metadata = EntityHelper.GetEntityTypeMetadata(typeof(EntityWithThrowingAccessors)); - /// - /// An entity whose property accessors throw, used to prove that creating metadata does not invoke them. - /// - private sealed class EntityWithThrowingAccessors + var property = metadata.MappedProperties.Single(p => + p.PropertyName == nameof(EntityWithThrowingAccessors.Value) + ); + + property.PropertyGetter.Should().NotBeNull(); + + // The accessor is real - it simply had not been called yet. + Invoking(() => property.PropertyGetter!(new EntityWithThrowingAccessors())) + .Should() + .Throw() + .WithMessage("Getter was invoked."); + } + + [Fact] + public void ShouldGuardAgainstNullArguments() { - public int Value - { - get => throw new InvalidOperationException("Getter was invoked."); - set => throw new InvalidOperationException("Setter was invoked."); - } + (string Name, Type Type)[] constructorParameters = + [ + ("a", typeof(short)), + ("b", typeof(int)), + ("c", typeof(long)), + ]; + + ArgumentNullGuardVerifier.Verify(() => + EntityHelper.FindCompatibleConstructor(typeof(ItemWithConstructor), constructorParameters) + ); + ArgumentNullGuardVerifier.Verify(() => EntityHelper.FindParameterlessConstructor(typeof(ItemWithConstructor))); + ArgumentNullGuardVerifier.Verify(() => EntityHelper.GetEntityTypeMetadata(typeof(Entity))); } /// @@ -529,4 +517,16 @@ private sealed class EntityWithNonPublicSetter public int Value { get; private set; } #pragma warning restore RCS1170 } + + /// + /// An entity whose property accessors throw, used to prove that creating metadata does not invoke them. + /// + private sealed class EntityWithThrowingAccessors + { + public int Value + { + get => throw new InvalidOperationException("Getter was invoked."); + set => throw new InvalidOperationException("Setter was invoked."); + } + } } diff --git a/tests/DbConnectionPlus.UnitTests/Extensions/ObjectExtensionsTests.cs b/tests/DbConnectionPlus.UnitTests/Extensions/ObjectExtensionsTests.cs index dfc397d..e651843 100644 --- a/tests/DbConnectionPlus.UnitTests/Extensions/ObjectExtensionsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Extensions/ObjectExtensionsTests.cs @@ -9,13 +9,6 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.Extensions; public class ObjectExtensionsTests : UnitTestsBase { - [Fact] - public void ToDebugString_ShouldUseToStringForUnhandledTypes() => - new Item("A") - .ToDebugString() - .Should() - .Be("'Item A' (RentADeveloper.DbConnectionPlus.UnitTests.Extensions.ObjectExtensionsTests+Item)"); - [Fact] public void ToDebugString_ShouldRenderSequencesElementByElement() { @@ -37,22 +30,6 @@ public void ToDebugString_ShouldRenderSequencesElementByElement() Array.Empty().ToDebugString().Should().Be("'[]' (System.Int32[])"); } - [Fact] - public void ToDebugString_ShouldTruncateSelfReferencingSequencesInsteadOfRecursingForever() - { - var values = new List { 1 }; - - values.Add(values); - - // The depth bound replaces the cycle handling that the previous JsonSerializer-based implementation got - // from ReferenceHandler.IgnoreCycles. What matters is that this terminates at all; the exact nesting - // depth at which it stops is an implementation detail. - var debugString = values.ToDebugString(); - - debugString.Should().StartWith("'[1,[1,[1,"); - debugString.Should().Contain("[...]"); - } - [Fact] public void ToDebugString_ShouldReturnStringRepresentationOfValue() { @@ -139,6 +116,29 @@ public void ToDebugString_ShouldReturnStringRepresentationOfValue() ); } + [Fact] + public void ToDebugString_ShouldTruncateSelfReferencingSequencesInsteadOfRecursingForever() + { + var values = new List { 1 }; + + values.Add(values); + + // The depth bound replaces the cycle handling that the previous JsonSerializer-based implementation got + // from ReferenceHandler.IgnoreCycles. What matters is that this terminates at all; the exact nesting + // depth at which it stops is an implementation detail. + var debugString = values.ToDebugString(); + + debugString.Should().StartWith("'[1,[1,[1,"); + debugString.Should().Contain("[...]"); + } + + [Fact] + public void ToDebugString_ShouldUseToStringForUnhandledTypes() => + new Item("A") + .ToDebugString() + .Should() + .Be("'Item A' (RentADeveloper.DbConnectionPlus.UnitTests.Extensions.ObjectExtensionsTests+Item)"); + private sealed class Item(string id) { /// diff --git a/tests/DbConnectionPlus.UnitTests/Materializers/EntityMaterializerFactoryTests.cs b/tests/DbConnectionPlus.UnitTests/Materializers/EntityMaterializerFactoryTests.cs index f5df77e..f5f38aa 100644 --- a/tests/DbConnectionPlus.UnitTests/Materializers/EntityMaterializerFactoryTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Materializers/EntityMaterializerFactoryTests.cs @@ -63,6 +63,25 @@ public void GetMaterializer_DataReaderHasNoFields_ShouldThrow() .WithMessage("The SQL statement did not return any columns.*"); } + [Fact] + public void GetMaterializer_DataReaderHasUnsupportedFieldType_ShouldThrow() + { + var dataReader = Substitute.For(); + + dataReader.FieldCount.Returns(1); + + dataReader.GetName(0).Returns("Value"); + dataReader.GetFieldType(0).Returns(typeof(BigInteger)); + + Invoking(() => EntityMaterializerFactory.GetMaterializer(dataReader)) + .Should() + .Throw() + .WithMessage( + $"The data type {typeof(BigInteger)} of the column 'Value' returned by the SQL statement is not " + + "supported.*" + ); + } + [Fact] public void GetMaterializer_NoFieldMatchesAWritableProperty_ShouldThrow() { @@ -101,25 +120,6 @@ public void GetMaterializer_SomeFieldsMatchAWritableProperty_ShouldNotThrow() Invoking(() => EntityMaterializerFactory.GetMaterializer(dataReader)).Should().NotThrow(); } - [Fact] - public void GetMaterializer_DataReaderHasUnsupportedFieldType_ShouldThrow() - { - var dataReader = Substitute.For(); - - dataReader.FieldCount.Returns(1); - - dataReader.GetName(0).Returns("Value"); - dataReader.GetFieldType(0).Returns(typeof(BigInteger)); - - Invoking(() => EntityMaterializerFactory.GetMaterializer(dataReader)) - .Should() - .Throw() - .WithMessage( - $"The data type {typeof(BigInteger)} of the column 'Value' returned by the SQL statement is not " - + "supported.*" - ); - } - [Fact] public void Materializer_CharEntityProperty_DataReaderFieldContainsStringWithLengthNotOne_ShouldThrow() { @@ -303,27 +303,6 @@ public void Materializer_EntityHasNoCorrespondingPropertyForDataReaderField_Shou entity.Int32Value.Should().Be(value); } - [Fact] - public void Materializer_EnumEntityProperty_DataReaderFieldContainsInteger_ShouldConvertToEnumMember() - { - var dataReader = Substitute.For(); - - var enumValue = Generate.Single(); - - dataReader.FieldCount.Returns(1); - - dataReader.GetName(0).Returns("Enum"); - dataReader.GetFieldType(0).Returns(typeof(int)); - dataReader.IsDBNull(0).Returns(false); - dataReader.GetInt32(0).Returns((int)enumValue); - - var materializer = EntityMaterializerFactory.GetMaterializer(dataReader); - - var entity = materializer(dataReader); - - entity.Enum.Should().Be(enumValue); - } - [Fact] public void Materializer_EnumEntityProperty_DataReaderFieldContainsIntegerNotMatchingAnyEnumMemberValue_ShouldThrow() { @@ -354,7 +333,7 @@ public void Materializer_EnumEntityProperty_DataReaderFieldContainsIntegerNotMat } [Fact] - public void Materializer_EnumEntityProperty_DataReaderFieldContainsString_ShouldConvertToEnumMember() + public void Materializer_EnumEntityProperty_DataReaderFieldContainsInteger_ShouldConvertToEnumMember() { var dataReader = Substitute.For(); @@ -363,11 +342,11 @@ public void Materializer_EnumEntityProperty_DataReaderFieldContainsString_Should dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("Enum"); - dataReader.GetFieldType(0).Returns(typeof(string)); + dataReader.GetFieldType(0).Returns(typeof(int)); dataReader.IsDBNull(0).Returns(false); - dataReader.GetString(0).Returns(enumValue.ToString()); + dataReader.GetInt32(0).Returns((int)enumValue); - var materializer = EntityMaterializerFactory.GetMaterializer(dataReader); + var materializer = EntityMaterializerFactory.GetMaterializer(dataReader); var entity = materializer(dataReader); @@ -403,6 +382,27 @@ public void Materializer_EnumEntityProperty_DataReaderFieldContainsStringNotMatc ); } + [Fact] + public void Materializer_EnumEntityProperty_DataReaderFieldContainsString_ShouldConvertToEnumMember() + { + var dataReader = Substitute.For(); + + var enumValue = Generate.Single(); + + dataReader.FieldCount.Returns(1); + + dataReader.GetName(0).Returns("Enum"); + dataReader.GetFieldType(0).Returns(typeof(string)); + dataReader.IsDBNull(0).Returns(false); + dataReader.GetString(0).Returns(enumValue.ToString()); + + var materializer = EntityMaterializerFactory.GetMaterializer(dataReader); + + var entity = materializer(dataReader); + + entity.Enum.Should().Be(enumValue); + } + [Fact] public void Materializer_Mapping_Attributes_ShouldUseAttributesMapping() { @@ -746,7 +746,7 @@ public void Materializer_ShouldMaterializeDateTimeOffsetValue() } [Fact] - public void ReflectionMaterializer_ShouldMaterializeTheSameEntityAsTheExpressionMaterializer() + public void ReflectionMaterializer_CompatiblePrivateConstructor_ShouldUsePrivateConstructor() { var entities = Generate.Multiple(1); @@ -754,8 +754,22 @@ public void ReflectionMaterializer_ShouldMaterializeTheSameEntityAsTheExpression dataReader.Read(); - var expressionMaterializer = EntityMaterializerFactory.GetMaterializer(dataReader); - var reflectionMaterializer = GetReflectionMaterializer(dataReader); + var materializer = GetReflectionMaterializer(dataReader); + + materializer(dataReader).Should().BeEquivalentTo(entities[0]); + } + + [Fact] + public void ReflectionMaterializer_CompatiblePublicConstructor_ShouldUsePublicConstructor() + { + var entities = Generate.Multiple(1); + + var dataReader = CreateEntityDataReader(entities); + + dataReader.Read(); + + var expressionMaterializer = EntityMaterializerFactory.GetMaterializer(dataReader); + var reflectionMaterializer = GetReflectionMaterializer(dataReader); var materializedEntity = reflectionMaterializer(dataReader); @@ -765,43 +779,69 @@ public void ReflectionMaterializer_ShouldMaterializeTheSameEntityAsTheExpression } [Fact] - public void ReflectionMaterializer_Mapping_Attributes_ShouldUseAttributesMapping() + public void ReflectionMaterializer_ConstructorParameterValueCannotBeConverted_ShouldThrow() { - var entity = Generate.Single(); + var dataReader = CreateItemDataReader(); - var dataReader = Substitute.For(); + dataReader.GetString(2).Returns("NonExistent"); - dataReader.FieldCount.Returns(3); + var expectedMessage = + "The column 'Enum' returned by the SQL statement contains a value that could not be converted to the " + + $"type {typeof(TestEnum)} of the corresponding property of the type {typeof(Item)}. See inner " + + "exception for details.*"; - var ordinal = 0; - dataReader.GetName(ordinal).Returns("Key1"); - dataReader.GetFieldType(ordinal).Returns(typeof(long)); - dataReader.IsDBNull(ordinal).Returns(false); - dataReader.GetInt64(ordinal).Returns(entity.Key1_); + var expectedInnerMessage = + $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. That " + + "string does not match any of the names of the enum's members.*"; - ordinal++; - dataReader.GetName(ordinal).Returns("Value"); - dataReader.GetFieldType(ordinal).Returns(typeof(int)); - dataReader.IsDBNull(ordinal).Returns(false); - dataReader.GetInt32(ordinal).Returns(entity.Value_); + var reflectionMaterializer = GetReflectionMaterializer(dataReader); + var expressionMaterializer = EntityMaterializerFactory.GetMaterializer(dataReader); - ordinal++; - var notMappedColumnOrdinal = ordinal; - dataReader.GetName(notMappedColumnOrdinal).Returns("NotMapped"); - dataReader.GetFieldType(notMappedColumnOrdinal).Returns(typeof(string)); + Invoking(() => reflectionMaterializer(dataReader)) + .Should() + .Throw() + .WithMessage(expectedMessage) + .WithInnerException() + .WithMessage(expectedInnerMessage); - var materializer = GetReflectionMaterializer(dataReader); + Invoking(() => expressionMaterializer(dataReader)) + .Should() + .Throw() + .WithMessage(expectedMessage) + .WithInnerException() + .WithMessage(expectedInnerMessage); + } - var materializedEntity = materializer(dataReader); + [Fact] + public void ReflectionMaterializer_ConstructorParametersInADifferentOrderThanTheFields_ShouldMaterialize() + { + var enumValue = Generate.Single(); + var name = Generate.Single(); + var id = Generate.Id(); - _ = dataReader.DidNotReceive().IsDBNull(notMappedColumnOrdinal); - _ = dataReader.DidNotReceive().GetString(notMappedColumnOrdinal); + // Item's constructor is (Id, Name, Enum); the result set deliberately returns the columns in another order. + var dataReader = Substitute.For(); - materializedEntity.Key1_.Should().Be(entity.Key1_); + dataReader.FieldCount.Returns(3); - materializedEntity.Value_.Should().Be(entity.Value_); + dataReader.GetName(0).Returns("Name"); + dataReader.GetFieldType(0).Returns(typeof(string)); + dataReader.IsDBNull(0).Returns(false); + dataReader.GetString(0).Returns(name); - materializedEntity.NotMapped.Should().BeNull(); + dataReader.GetName(1).Returns("Enum"); + dataReader.GetFieldType(1).Returns(typeof(int)); // Item.Enum is of type TestEnum. + dataReader.IsDBNull(1).Returns(false); + dataReader.GetInt32(1).Returns((int)enumValue); + + dataReader.GetName(2).Returns("Id"); + dataReader.GetFieldType(2).Returns(typeof(long)); + dataReader.IsDBNull(2).Returns(false); + dataReader.GetInt64(2).Returns(id); + + var materializer = GetReflectionMaterializer(dataReader); + + materializer(dataReader).Should().Be(new Item(id, name, enumValue)); } [Fact] @@ -821,35 +861,6 @@ public void ReflectionMaterializer_DataReaderFieldNameMatchesEntityPropertyCaseI materializer(dataReader).Id.Should().Be(789); } - [Fact] - public void ReflectionMaterializer_DataReaderHasCompatibleFieldTypes_ShouldConvertValues() - { - var dataReader = Substitute.For(); - - var entityId = Generate.Id(); - var enumValue = Generate.Single(); - - dataReader.FieldCount.Returns(2); - - dataReader.GetName(0).Returns("Id"); - dataReader.GetFieldType(0).Returns(typeof(string)); // EntityWithEnumStoredAsInteger.Id is of type Int64. - dataReader.IsDBNull(0).Returns(false); - dataReader.GetString(0).Returns(entityId.ToString()); - - dataReader.GetName(1).Returns("Enum"); - dataReader.GetFieldType(1).Returns(typeof(decimal)); // EntityWithEnumStoredAsInteger.Enum is of type TestEnum. - dataReader.IsDBNull(1).Returns(false); - dataReader.GetDecimal(1).Returns((decimal)enumValue); - - var materializer = GetReflectionMaterializer(dataReader); - - var entity = materializer(dataReader); - - entity.Id.Should().Be(entityId); - - entity.Enum.Should().Be(enumValue); - } - [Fact] public void ReflectionMaterializer_DataReaderFieldValueCannotBeConverted_ShouldThrow() { @@ -880,135 +891,72 @@ public void ReflectionMaterializer_DataReaderFieldValueCannotBeConverted_ShouldT } [Fact] - public void ReflectionMaterializer_NonNullableEntityProperty_DataReaderFieldContainsNull_ShouldThrow() + public void ReflectionMaterializer_DataReaderHasCompatibleFieldTypes_ShouldConvertValues() { var dataReader = Substitute.For(); - dataReader.FieldCount.Returns(1); - - dataReader.GetName(0).Returns("Id"); - dataReader.GetFieldType(0).Returns(typeof(long)); - dataReader.IsDBNull(0).Returns(true); - - var materializer = GetReflectionMaterializer(dataReader); + var entityId = Generate.Id(); + var enumValue = Generate.Single(); - Invoking(() => materializer(dataReader)) - .Should() - .Throw() - .WithMessage( - "The column 'Id' returned by the SQL statement contains a NULL value, but the corresponding " - + $"property of the type {typeof(Entity)} is non-nullable.*" - ); - } + dataReader.FieldCount.Returns(2); - [Fact] - public void ReflectionMaterializer_NullableEntityProperty_DataReaderFieldContainsNull_ShouldMaterializeNull() - { - var dataReader = Substitute.For(); + dataReader.GetName(0).Returns("Id"); + dataReader.GetFieldType(0).Returns(typeof(string)); // EntityWithEnumStoredAsInteger.Id is of type Int64. + dataReader.IsDBNull(0).Returns(false); + dataReader.GetString(0).Returns(entityId.ToString()); - dataReader.FieldCount.Returns(1); + dataReader.GetName(1).Returns("Enum"); + dataReader.GetFieldType(1).Returns(typeof(decimal)); // EntityWithEnumStoredAsInteger.Enum is of type TestEnum. + dataReader.IsDBNull(1).Returns(false); + dataReader.GetDecimal(1).Returns((decimal)enumValue); - dataReader.GetName(0).Returns("NullableBooleanValue"); - dataReader.GetFieldType(0).Returns(typeof(bool)); - dataReader.IsDBNull(0).Returns(true); - dataReader.GetBoolean(0).Throws(new SqlNullValueException()); + var materializer = GetReflectionMaterializer(dataReader); - var materializer = GetReflectionMaterializer(dataReader); + var entity = materializer(dataReader); - var entity = Invoking(() => materializer(dataReader)).Should().NotThrow().Subject; + entity.Id.Should().Be(entityId); - entity.NullableBooleanValue.Should().BeNull(); + entity.Enum.Should().Be(enumValue); } [Fact] - public void ReflectionMaterializer_ShouldMaterializeDateTimeOffsetValue() + public void ReflectionMaterializer_Mapping_Attributes_ShouldUseAttributesMapping() { - var entity = Generate.Single(); + var entity = Generate.Single(); var dataReader = Substitute.For(); - dataReader.FieldCount.Returns(2); + dataReader.FieldCount.Returns(3); var ordinal = 0; - dataReader.GetName(ordinal).Returns("Id"); + dataReader.GetName(ordinal).Returns("Key1"); dataReader.GetFieldType(ordinal).Returns(typeof(long)); dataReader.IsDBNull(ordinal).Returns(false); - dataReader.GetInt64(ordinal).Returns(entity.Id); + dataReader.GetInt64(ordinal).Returns(entity.Key1_); ordinal++; - dataReader.GetName(ordinal).Returns("DateTimeOffsetValue"); - dataReader.GetFieldType(ordinal).Returns(typeof(DateTimeOffset)); + dataReader.GetName(ordinal).Returns("Value"); + dataReader.GetFieldType(ordinal).Returns(typeof(int)); dataReader.IsDBNull(ordinal).Returns(false); - dataReader.GetValue(ordinal).Returns(entity.DateTimeOffsetValue); - - var materializer = GetReflectionMaterializer(dataReader); - - materializer(dataReader).Should().BeEquivalentTo(entity); - } - - [Fact] - public void ReflectionMaterializer_CompatiblePublicConstructor_ShouldUsePublicConstructor() - { - var entities = Generate.Multiple(1); - - var dataReader = CreateEntityDataReader(entities); - - dataReader.Read(); - - var expressionMaterializer = EntityMaterializerFactory.GetMaterializer(dataReader); - var reflectionMaterializer = GetReflectionMaterializer(dataReader); - - var materializedEntity = reflectionMaterializer(dataReader); - - materializedEntity.Should().BeEquivalentTo(entities[0]); - - materializedEntity.Should().BeEquivalentTo(expressionMaterializer(dataReader)); - } - - [Fact] - public void ReflectionMaterializer_CompatiblePrivateConstructor_ShouldUsePrivateConstructor() - { - var entities = Generate.Multiple(1); - - var dataReader = CreateEntityDataReader(entities); - - dataReader.Read(); - - var materializer = GetReflectionMaterializer(dataReader); - - materializer(dataReader).Should().BeEquivalentTo(entities[0]); - } - - [Fact] - public void ReflectionMaterializer_ConstructorParametersInADifferentOrderThanTheFields_ShouldMaterialize() - { - var enumValue = Generate.Single(); - var name = Generate.Single(); - var id = Generate.Id(); + dataReader.GetInt32(ordinal).Returns(entity.Value_); - // Item's constructor is (Id, Name, Enum); the result set deliberately returns the columns in another order. - var dataReader = Substitute.For(); + ordinal++; + var notMappedColumnOrdinal = ordinal; + dataReader.GetName(notMappedColumnOrdinal).Returns("NotMapped"); + dataReader.GetFieldType(notMappedColumnOrdinal).Returns(typeof(string)); - dataReader.FieldCount.Returns(3); + var materializer = GetReflectionMaterializer(dataReader); - dataReader.GetName(0).Returns("Name"); - dataReader.GetFieldType(0).Returns(typeof(string)); - dataReader.IsDBNull(0).Returns(false); - dataReader.GetString(0).Returns(name); + var materializedEntity = materializer(dataReader); - dataReader.GetName(1).Returns("Enum"); - dataReader.GetFieldType(1).Returns(typeof(int)); // Item.Enum is of type TestEnum. - dataReader.IsDBNull(1).Returns(false); - dataReader.GetInt32(1).Returns((int)enumValue); + _ = dataReader.DidNotReceive().IsDBNull(notMappedColumnOrdinal); + _ = dataReader.DidNotReceive().GetString(notMappedColumnOrdinal); - dataReader.GetName(2).Returns("Id"); - dataReader.GetFieldType(2).Returns(typeof(long)); - dataReader.IsDBNull(2).Returns(false); - dataReader.GetInt64(2).Returns(id); + materializedEntity.Key1_.Should().Be(entity.Key1_); - var materializer = GetReflectionMaterializer(dataReader); + materializedEntity.Value_.Should().Be(entity.Value_); - materializer(dataReader).Should().Be(new Item(id, name, enumValue)); + materializedEntity.NotMapped.Should().BeNull(); } [Fact] @@ -1036,6 +984,28 @@ public void ReflectionMaterializer_NonNullableConstructorParameter_DataReaderFie .WithMessage(expectedMessage); } + [Fact] + public void ReflectionMaterializer_NonNullableEntityProperty_DataReaderFieldContainsNull_ShouldThrow() + { + var dataReader = Substitute.For(); + + dataReader.FieldCount.Returns(1); + + dataReader.GetName(0).Returns("Id"); + dataReader.GetFieldType(0).Returns(typeof(long)); + dataReader.IsDBNull(0).Returns(true); + + var materializer = GetReflectionMaterializer(dataReader); + + Invoking(() => materializer(dataReader)) + .Should() + .Throw() + .WithMessage( + "The column 'Id' returned by the SQL statement contains a NULL value, but the corresponding " + + $"property of the type {typeof(Entity)} is non-nullable.*" + ); + } + [Fact] public void ReflectionMaterializer_NullableConstructorParameter_DataReaderFieldContainsNull_ShouldPassNull() { @@ -1049,37 +1019,22 @@ public void ReflectionMaterializer_NullableConstructorParameter_DataReaderFieldC } [Fact] - public void ReflectionMaterializer_ConstructorParameterValueCannotBeConverted_ShouldThrow() + public void ReflectionMaterializer_NullableEntityProperty_DataReaderFieldContainsNull_ShouldMaterializeNull() { - var dataReader = CreateItemDataReader(); - - dataReader.GetString(2).Returns("NonExistent"); + var dataReader = Substitute.For(); - var expectedMessage = - "The column 'Enum' returned by the SQL statement contains a value that could not be converted to the " - + $"type {typeof(TestEnum)} of the corresponding property of the type {typeof(Item)}. See inner " - + "exception for details.*"; + dataReader.FieldCount.Returns(1); - var expectedInnerMessage = - $"Could not convert the string 'NonExistent' to an enum member of the type {typeof(TestEnum)}. That " - + "string does not match any of the names of the enum's members.*"; + dataReader.GetName(0).Returns("NullableBooleanValue"); + dataReader.GetFieldType(0).Returns(typeof(bool)); + dataReader.IsDBNull(0).Returns(true); + dataReader.GetBoolean(0).Throws(new SqlNullValueException()); - var reflectionMaterializer = GetReflectionMaterializer(dataReader); - var expressionMaterializer = EntityMaterializerFactory.GetMaterializer(dataReader); + var materializer = GetReflectionMaterializer(dataReader); - Invoking(() => reflectionMaterializer(dataReader)) - .Should() - .Throw() - .WithMessage(expectedMessage) - .WithInnerException() - .WithMessage(expectedInnerMessage); + var entity = Invoking(() => materializer(dataReader)).Should().NotThrow().Subject; - Invoking(() => expressionMaterializer(dataReader)) - .Should() - .Throw() - .WithMessage(expectedMessage) - .WithInnerException() - .WithMessage(expectedInnerMessage); + entity.NullableBooleanValue.Should().BeNull(); } [Fact] @@ -1096,6 +1051,51 @@ public void ReflectionMaterializer_PrivateParameterlessConstructor_ShouldUsePriv materializer(dataReader).Should().BeEquivalentTo(entities[0]); } + [Fact] + public void ReflectionMaterializer_ShouldMaterializeDateTimeOffsetValue() + { + var entity = Generate.Single(); + + var dataReader = Substitute.For(); + + dataReader.FieldCount.Returns(2); + + var ordinal = 0; + dataReader.GetName(ordinal).Returns("Id"); + dataReader.GetFieldType(ordinal).Returns(typeof(long)); + dataReader.IsDBNull(ordinal).Returns(false); + dataReader.GetInt64(ordinal).Returns(entity.Id); + + ordinal++; + dataReader.GetName(ordinal).Returns("DateTimeOffsetValue"); + dataReader.GetFieldType(ordinal).Returns(typeof(DateTimeOffset)); + dataReader.IsDBNull(ordinal).Returns(false); + dataReader.GetValue(ordinal).Returns(entity.DateTimeOffsetValue); + + var materializer = GetReflectionMaterializer(dataReader); + + materializer(dataReader).Should().BeEquivalentTo(entity); + } + + [Fact] + public void ReflectionMaterializer_ShouldMaterializeTheSameEntityAsTheExpressionMaterializer() + { + var entities = Generate.Multiple(1); + + var dataReader = CreateEntityDataReader(entities); + + dataReader.Read(); + + var expressionMaterializer = EntityMaterializerFactory.GetMaterializer(dataReader); + var reflectionMaterializer = GetReflectionMaterializer(dataReader); + + var materializedEntity = reflectionMaterializer(dataReader); + + materializedEntity.Should().BeEquivalentTo(entities[0]); + + materializedEntity.Should().BeEquivalentTo(expressionMaterializer(dataReader)); + } + [Fact] public void ShouldGuardAgainstNullArguments() { @@ -1114,6 +1114,18 @@ public void ShouldGuardAgainstNullArguments() ); } + /// + /// Creates a multi-column reader over the mapped, readable properties of . + /// + /// The entities the reader reads. + /// The created reader. + private static EnumerableReader CreateEntityDataReader(IEnumerable entities) => + new( + entities, + [.. EntityHelper.GetEntityTypeMetadata(typeof(Entity)).MappedProperties.Where(a => a.CanRead)], + EnumerableReaderOptions.SerializeEnums | EnumerableReaderOptions.ReadCharsAsStrings + ); + /// /// Creates a data reader whose three columns match the constructor of , so that both /// materializers take the constructor-injection strategy. @@ -1143,18 +1155,6 @@ private static DbDataReader CreateItemDataReader() return dataReader; } - /// - /// Creates a multi-column reader over the mapped, readable properties of . - /// - /// The entities the reader reads. - /// The created reader. - private static EnumerableReader CreateEntityDataReader(IEnumerable entities) => - new( - entities, - [.. EntityHelper.GetEntityTypeMetadata(typeof(Entity)).MappedProperties.Where(a => a.CanRead)], - EnumerableReaderOptions.SerializeEnums | EnumerableReaderOptions.ReadCharsAsStrings - ); - /// /// Creates the reflection materializer - the one that serves applications published with Native AOT - for the /// shape of . diff --git a/tests/DbConnectionPlus.UnitTests/Materializers/ValueTupleMaterializerFactoryTests.cs b/tests/DbConnectionPlus.UnitTests/Materializers/ValueTupleMaterializerFactoryTests.cs index edd1e6a..1664d9b 100644 --- a/tests/DbConnectionPlus.UnitTests/Materializers/ValueTupleMaterializerFactoryTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Materializers/ValueTupleMaterializerFactoryTests.cs @@ -144,27 +144,6 @@ public void Materializer_DataReaderHasCompatibleFieldTypes_ShouldConvertValues() entity.Enum.Should().Be(enumValue); } - [Fact] - public void Materializer_EnumValueTupleField_DataReaderContainsInteger_ShouldConvertToEnumMember() - { - var dataReader = Substitute.For(); - - var enumValue = Generate.Single(); - - dataReader.FieldCount.Returns(1); - - dataReader.GetName(0).Returns("Enum"); - dataReader.GetFieldType(0).Returns(typeof(int)); - dataReader.IsDBNull(0).Returns(false); - dataReader.GetInt32(0).Returns((int)enumValue); - - var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); - - var valueTuple = materializer(dataReader); - - valueTuple.Item1.Should().Be(enumValue); - } - [Fact] public void Materializer_EnumValueTupleField_DataReaderContainsIntegerNotMatchingAnyEnumMemberValue_ShouldThrow() { @@ -195,7 +174,7 @@ public void Materializer_EnumValueTupleField_DataReaderContainsIntegerNotMatchin } [Fact] - public void Materializer_EnumValueTupleField_DataReaderContainsString_ShouldConvertToEnumMember() + public void Materializer_EnumValueTupleField_DataReaderContainsInteger_ShouldConvertToEnumMember() { var dataReader = Substitute.For(); @@ -204,9 +183,9 @@ public void Materializer_EnumValueTupleField_DataReaderContainsString_ShouldConv dataReader.FieldCount.Returns(1); dataReader.GetName(0).Returns("Enum"); - dataReader.GetFieldType(0).Returns(typeof(string)); + dataReader.GetFieldType(0).Returns(typeof(int)); dataReader.IsDBNull(0).Returns(false); - dataReader.GetString(0).Returns(enumValue.ToString()); + dataReader.GetInt32(0).Returns((int)enumValue); var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); @@ -244,6 +223,27 @@ public void Materializer_EnumValueTupleField_DataReaderContainsStringNotMatching ); } + [Fact] + public void Materializer_EnumValueTupleField_DataReaderContainsString_ShouldConvertToEnumMember() + { + var dataReader = Substitute.For(); + + var enumValue = Generate.Single(); + + dataReader.FieldCount.Returns(1); + + dataReader.GetName(0).Returns("Enum"); + dataReader.GetFieldType(0).Returns(typeof(string)); + dataReader.IsDBNull(0).Returns(false); + dataReader.GetString(0).Returns(enumValue.ToString()); + + var materializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); + + var valueTuple = materializer(dataReader); + + valueTuple.Item1.Should().Be(enumValue); + } + [Fact] public void Materializer_MoreThan7FieldsValueTupleType_ShouldMaterializeNestedValueTuples() { @@ -604,87 +604,128 @@ public void Materializer_ShouldSupportSingleFieldValueTupleType() } [Fact] - public void ReflectionMaterializer_ShouldMaterializeTheSameValueTupleAsTheExpressionMaterializer() + public void ReflectionMaterializer_DataReaderFieldHasNoName_ShouldReportThePositionOfTheField() { - var entity = Generate.Single(); - var dataReader = Substitute.For(); - dataReader.FieldCount.Returns(7); - - var ordinal = 0; + dataReader.FieldCount.Returns(2); - dataReader.GetName(ordinal).Returns("Boolean"); - dataReader.GetFieldType(ordinal).Returns(typeof(bool)); - dataReader.IsDBNull(ordinal).Returns(false); - dataReader.GetBoolean(ordinal).Returns(entity.BooleanValue); + dataReader.GetName(0).Returns(""); + dataReader.GetFieldType(0).Returns(typeof(long)); + dataReader.IsDBNull(0).Returns(false); + dataReader.GetInt64(0).Returns(Generate.Id()); - ordinal++; - dataReader.GetName(ordinal).Returns("Char"); - dataReader.GetFieldType(ordinal).Returns(typeof(string)); - dataReader.IsDBNull(ordinal).Returns(false); - dataReader.GetString(ordinal).Returns(entity.CharValue.ToString()); + dataReader.GetName(1).Returns(""); + dataReader.GetFieldType(1).Returns(typeof(long)); + dataReader.IsDBNull(1).Returns(true); - ordinal++; - dataReader.GetName(ordinal).Returns("DateTime"); - dataReader.GetFieldType(ordinal).Returns(typeof(DateTime)); - dataReader.IsDBNull(ordinal).Returns(false); - dataReader.GetDateTime(ordinal).Returns(entity.DateTimeValue); + var expressionMaterializer = ValueTupleMaterializerFactory.GetMaterializer<(long, long)>(dataReader); + var reflectionMaterializer = GetReflectionMaterializer<(long, long)>(dataReader); - ordinal++; - dataReader.GetName(ordinal).Returns("Nullable"); - dataReader.GetFieldType(ordinal).Returns(typeof(decimal)); - dataReader.IsDBNull(ordinal).Returns(true); + var expectedMessage = Invoking(() => expressionMaterializer(dataReader)) + .Should() + .Throw() + .Which.Message; - ordinal++; - dataReader.GetName(ordinal).Returns("Enum"); - dataReader.GetFieldType(ordinal).Returns(typeof(string)); - dataReader.IsDBNull(ordinal).Returns(false); - dataReader.GetString(ordinal).Returns(entity.EnumValue.ToString()); + Invoking(() => reflectionMaterializer(dataReader)) + .Should() + .Throw() + .WithMessage( + "The 2nd column returned by the SQL statement contains a NULL value, but the corresponding field " + + $"of the value tuple type {typeof((long, long))} is non-nullable." + ) + .And.Message.Should() + .Be(expectedMessage); + } - ordinal++; - dataReader.GetName(ordinal).Returns("Guid"); - dataReader.GetFieldType(ordinal).Returns(typeof(Guid)); - dataReader.IsDBNull(ordinal).Returns(false); - dataReader.GetGuid(ordinal).Returns(entity.GuidValue); + [Fact] + public void ReflectionMaterializer_DataReaderFieldValueCannotBeConverted_ShouldThrow() + { + var dataReader = Substitute.For(); - ordinal++; - dataReader.GetName(ordinal).Returns("Int32"); - dataReader.GetFieldType(ordinal).Returns(typeof(int)); - dataReader.IsDBNull(ordinal).Returns(false); - dataReader.GetInt32(ordinal).Returns(entity.Int32Value); + dataReader.FieldCount.Returns(1); - var expressionMaterializer = ValueTupleMaterializerFactory.GetMaterializer<( - bool, - char, - DateTime, - decimal?, - TestEnum, - Guid, - int - )>(dataReader); + dataReader.GetName(0).Returns("Enum"); + dataReader.GetFieldType(0).Returns(typeof(int)); + dataReader.IsDBNull(0).Returns(false); + dataReader.GetInt32(0).Returns(999); - var reflectionMaterializer = GetReflectionMaterializer<(bool, char, DateTime, decimal?, TestEnum, Guid, int)>( - dataReader - ); + var expressionMaterializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); + var reflectionMaterializer = GetReflectionMaterializer>(dataReader); - var valueTuple = reflectionMaterializer(dataReader); + var expectedMessage = Invoking(() => expressionMaterializer(dataReader)) + .Should() + .Throw() + .Which.Message; - valueTuple + Invoking(() => reflectionMaterializer(dataReader)) .Should() - .Be( - ( - entity.BooleanValue, - entity.CharValue, - entity.DateTimeValue, - (decimal?)null, - entity.EnumValue, - entity.GuidValue, - entity.Int32Value - ) + .Throw() + .WithMessage( + "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " + + $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " + + $"{typeof(ValueTuple)}. See inner exception for details.*" + ) + .WithInnerException() + .WithMessage( + $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " + + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" ); - valueTuple.Should().Be(expressionMaterializer(dataReader)); + Invoking(() => reflectionMaterializer(dataReader)) + .Should() + .Throw() + .Which.Message.Should() + .Be(expectedMessage); + } + + [Fact] + public void ReflectionMaterializer_DataReaderHasCompatibleFieldTypes_ShouldConvertValues() + { + var dataReader = Substitute.For(); + + var entityId = Generate.Id(); + var enumValue = Generate.Single(); + + dataReader.FieldCount.Returns(2); + + dataReader.GetName(0).Returns("Id"); + dataReader.GetFieldType(0).Returns(typeof(string)); + dataReader.IsDBNull(0).Returns(false); + dataReader.GetString(0).Returns(entityId.ToString()); + + dataReader.GetName(1).Returns("Enum"); + dataReader.GetFieldType(1).Returns(typeof(decimal)); + dataReader.IsDBNull(1).Returns(false); + dataReader.GetDecimal(1).Returns((decimal)enumValue); + + var materializer = GetReflectionMaterializer<(long Id, TestEnum Enum)>(dataReader); + + var valueTuple = materializer(dataReader); + + valueTuple.Id.Should().Be(entityId); + + valueTuple.Enum.Should().Be(enumValue); + } + + [Fact] + public void ReflectionMaterializer_EightFieldsValueTupleType_ShouldMaterializeNestedValueTuple() + { + var dataReader = Substitute.For(); + + dataReader.FieldCount.Returns(8); + + for (var i = 0; i < 8; i++) + { + dataReader.GetName(i).Returns($"Value{i + 1}"); + dataReader.GetFieldType(i).Returns(typeof(int)); + dataReader.IsDBNull(i).Returns(false); + dataReader.GetInt32(i).Returns(i + 1); + } + + var materializer = GetReflectionMaterializer<(int, int, int, int, int, int, int, int)>(dataReader); + + materializer(dataReader).Should().Be((1, 2, 3, 4, 5, 6, 7, 8)); } [Fact] @@ -748,74 +789,6 @@ public void ReflectionMaterializer_MoreThan7FieldsValueTupleType_ShouldMateriali valueTuple.Rest.Rest.Item1.Should().Be(15); } - [Fact] - public void ReflectionMaterializer_EightFieldsValueTupleType_ShouldMaterializeNestedValueTuple() - { - var dataReader = Substitute.For(); - - dataReader.FieldCount.Returns(8); - - for (var i = 0; i < 8; i++) - { - dataReader.GetName(i).Returns($"Value{i + 1}"); - dataReader.GetFieldType(i).Returns(typeof(int)); - dataReader.IsDBNull(i).Returns(false); - dataReader.GetInt32(i).Returns(i + 1); - } - - var materializer = GetReflectionMaterializer<(int, int, int, int, int, int, int, int)>(dataReader); - - materializer(dataReader).Should().Be((1, 2, 3, 4, 5, 6, 7, 8)); - } - - [Fact] - public void ReflectionMaterializer_DataReaderHasCompatibleFieldTypes_ShouldConvertValues() - { - var dataReader = Substitute.For(); - - var entityId = Generate.Id(); - var enumValue = Generate.Single(); - - dataReader.FieldCount.Returns(2); - - dataReader.GetName(0).Returns("Id"); - dataReader.GetFieldType(0).Returns(typeof(string)); - dataReader.IsDBNull(0).Returns(false); - dataReader.GetString(0).Returns(entityId.ToString()); - - dataReader.GetName(1).Returns("Enum"); - dataReader.GetFieldType(1).Returns(typeof(decimal)); - dataReader.IsDBNull(1).Returns(false); - dataReader.GetDecimal(1).Returns((decimal)enumValue); - - var materializer = GetReflectionMaterializer<(long Id, TestEnum Enum)>(dataReader); - - var valueTuple = materializer(dataReader); - - valueTuple.Id.Should().Be(entityId); - - valueTuple.Enum.Should().Be(enumValue); - } - - [Fact] - public void ReflectionMaterializer_ShouldMaterializeBinaryData() - { - var dataReader = Substitute.For(); - - dataReader.FieldCount.Returns(1); - - var bytes = Generate.Single(); - - dataReader.GetName(0).Returns("Data"); - dataReader.GetFieldType(0).Returns(typeof(byte[])); - dataReader.IsDBNull(0).Returns(false); - dataReader.GetValue(0).Returns(bytes); - - var materializer = GetReflectionMaterializer>(dataReader); - - materializer(dataReader).Item1.Should().BeEquivalentTo(bytes); - } - [Fact] public void ReflectionMaterializer_NonNullableValueTupleField_DataReaderFieldContainsNull_ShouldThrow() { @@ -864,79 +837,106 @@ public void ReflectionMaterializer_NullableValueTupleField_DataReaderFieldContai } [Fact] - public void ReflectionMaterializer_DataReaderFieldValueCannotBeConverted_ShouldThrow() + public void ReflectionMaterializer_ShouldMaterializeBinaryData() { var dataReader = Substitute.For(); dataReader.FieldCount.Returns(1); - dataReader.GetName(0).Returns("Enum"); - dataReader.GetFieldType(0).Returns(typeof(int)); - dataReader.IsDBNull(0).Returns(false); - dataReader.GetInt32(0).Returns(999); - - var expressionMaterializer = ValueTupleMaterializerFactory.GetMaterializer>(dataReader); - var reflectionMaterializer = GetReflectionMaterializer>(dataReader); + var bytes = Generate.Single(); - var expectedMessage = Invoking(() => expressionMaterializer(dataReader)) - .Should() - .Throw() - .Which.Message; + dataReader.GetName(0).Returns("Data"); + dataReader.GetFieldType(0).Returns(typeof(byte[])); + dataReader.IsDBNull(0).Returns(false); + dataReader.GetValue(0).Returns(bytes); - Invoking(() => reflectionMaterializer(dataReader)) - .Should() - .Throw() - .WithMessage( - "The column 'Enum' returned by the SQL statement contains a value that could not be converted to " - + $"the type {typeof(TestEnum)} of the corresponding field of the value tuple type " - + $"{typeof(ValueTuple)}. See inner exception for details.*" - ) - .WithInnerException() - .WithMessage( - $"Could not convert the value '999' ({typeof(int)}) to an enum member of the type " - + $"{typeof(TestEnum)}. That value does not match any of the values of the enum's members.*" - ); + var materializer = GetReflectionMaterializer>(dataReader); - Invoking(() => reflectionMaterializer(dataReader)) - .Should() - .Throw() - .Which.Message.Should() - .Be(expectedMessage); + materializer(dataReader).Item1.Should().BeEquivalentTo(bytes); } [Fact] - public void ReflectionMaterializer_DataReaderFieldHasNoName_ShouldReportThePositionOfTheField() + public void ReflectionMaterializer_ShouldMaterializeTheSameValueTupleAsTheExpressionMaterializer() { + var entity = Generate.Single(); + var dataReader = Substitute.For(); - dataReader.FieldCount.Returns(2); + dataReader.FieldCount.Returns(7); - dataReader.GetName(0).Returns(""); - dataReader.GetFieldType(0).Returns(typeof(long)); - dataReader.IsDBNull(0).Returns(false); - dataReader.GetInt64(0).Returns(Generate.Id()); + var ordinal = 0; - dataReader.GetName(1).Returns(""); - dataReader.GetFieldType(1).Returns(typeof(long)); - dataReader.IsDBNull(1).Returns(true); + dataReader.GetName(ordinal).Returns("Boolean"); + dataReader.GetFieldType(ordinal).Returns(typeof(bool)); + dataReader.IsDBNull(ordinal).Returns(false); + dataReader.GetBoolean(ordinal).Returns(entity.BooleanValue); - var expressionMaterializer = ValueTupleMaterializerFactory.GetMaterializer<(long, long)>(dataReader); - var reflectionMaterializer = GetReflectionMaterializer<(long, long)>(dataReader); + ordinal++; + dataReader.GetName(ordinal).Returns("Char"); + dataReader.GetFieldType(ordinal).Returns(typeof(string)); + dataReader.IsDBNull(ordinal).Returns(false); + dataReader.GetString(ordinal).Returns(entity.CharValue.ToString()); - var expectedMessage = Invoking(() => expressionMaterializer(dataReader)) - .Should() - .Throw() - .Which.Message; + ordinal++; + dataReader.GetName(ordinal).Returns("DateTime"); + dataReader.GetFieldType(ordinal).Returns(typeof(DateTime)); + dataReader.IsDBNull(ordinal).Returns(false); + dataReader.GetDateTime(ordinal).Returns(entity.DateTimeValue); - Invoking(() => reflectionMaterializer(dataReader)) + ordinal++; + dataReader.GetName(ordinal).Returns("Nullable"); + dataReader.GetFieldType(ordinal).Returns(typeof(decimal)); + dataReader.IsDBNull(ordinal).Returns(true); + + ordinal++; + dataReader.GetName(ordinal).Returns("Enum"); + dataReader.GetFieldType(ordinal).Returns(typeof(string)); + dataReader.IsDBNull(ordinal).Returns(false); + dataReader.GetString(ordinal).Returns(entity.EnumValue.ToString()); + + ordinal++; + dataReader.GetName(ordinal).Returns("Guid"); + dataReader.GetFieldType(ordinal).Returns(typeof(Guid)); + dataReader.IsDBNull(ordinal).Returns(false); + dataReader.GetGuid(ordinal).Returns(entity.GuidValue); + + ordinal++; + dataReader.GetName(ordinal).Returns("Int32"); + dataReader.GetFieldType(ordinal).Returns(typeof(int)); + dataReader.IsDBNull(ordinal).Returns(false); + dataReader.GetInt32(ordinal).Returns(entity.Int32Value); + + var expressionMaterializer = ValueTupleMaterializerFactory.GetMaterializer<( + bool, + char, + DateTime, + decimal?, + TestEnum, + Guid, + int + )>(dataReader); + + var reflectionMaterializer = GetReflectionMaterializer<(bool, char, DateTime, decimal?, TestEnum, Guid, int)>( + dataReader + ); + + var valueTuple = reflectionMaterializer(dataReader); + + valueTuple .Should() - .Throw() - .WithMessage( - "The 2nd column returned by the SQL statement contains a NULL value, but the corresponding field " - + $"of the value tuple type {typeof((long, long))} is non-nullable." - ) - .And.Message.Should() - .Be(expectedMessage); + .Be( + ( + entity.BooleanValue, + entity.CharValue, + entity.DateTimeValue, + (decimal?)null, + entity.EnumValue, + entity.GuidValue, + entity.Int32Value + ) + ); + + valueTuple.Should().Be(expressionMaterializer(dataReader)); } [Fact] diff --git a/tests/DbConnectionPlus.UnitTests/Mocks/MockDbParameterCollection.cs b/tests/DbConnectionPlus.UnitTests/Mocks/MockDbParameterCollection.cs index 8721897..72da3f1 100644 --- a/tests/DbConnectionPlus.UnitTests/Mocks/MockDbParameterCollection.cs +++ b/tests/DbConnectionPlus.UnitTests/Mocks/MockDbParameterCollection.cs @@ -5,6 +5,8 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.Mocks; /// public class MockDbParameterCollection : DbParameterCollection { + private readonly List parameters = []; + /// public override int Count => this.parameters.Count; @@ -84,6 +86,4 @@ private int IndexOfChecked(string parameterName) var index = this.IndexOf(parameterName); return index != -1 ? index : throw new IndexOutOfRangeException(); } - - private readonly List parameters = []; } diff --git a/tests/DbConnectionPlus.UnitTests/Readers/CommandDisposingDataReaderDecoratorTests.cs b/tests/DbConnectionPlus.UnitTests/Readers/CommandDisposingDataReaderDecoratorTests.cs index 3c05f97..5de8818 100644 --- a/tests/DbConnectionPlus.UnitTests/Readers/CommandDisposingDataReaderDecoratorTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Readers/CommandDisposingDataReaderDecoratorTests.cs @@ -11,6 +11,11 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.Readers; public class CommandDisposingDataReaderDecoratorTests : UnitTestsBase { + private readonly DbCommandDisposer commandDisposer; + + private readonly DbDataReader decoratedReader; + private readonly CommandDisposingDataReaderDecorator decorator; + /// public CommandDisposingDataReaderDecoratorTests() { @@ -29,46 +34,46 @@ public CommandDisposingDataReaderDecoratorTests() } [Fact] - public void Dispose_ShouldDisposeCommandDisposer() + public async Task DisposeAsync_ShouldDisposeCommandDisposer() { - this.decorator.Dispose(); + await this.decorator.DisposeAsync(); - this.commandDisposer.Received().Dispose(); + await this.commandDisposer.Received().DisposeAsync(); } [Fact] - public async Task DisposeAsync_ShouldDisposeCommandDisposer() + public void Dispose_ShouldDisposeCommandDisposer() { - await this.decorator.DisposeAsync(); + this.decorator.Dispose(); - await this.commandDisposer.Received().DisposeAsync(); + this.commandDisposer.Received().Dispose(); } [Fact] - public void GetFieldValue_ShouldForwardToDecoratedReader() + public async Task GetFieldValueAsync_ShouldForwardToDecoratedReader() { var ordinal = Generate.SmallNumber(); var returnValue = Generate.SmallNumber(); - this.decoratedReader.GetFieldValue(ordinal).Returns(returnValue); + this.decoratedReader.GetFieldValueAsync(ordinal, CancellationToken.None) + .Returns(Task.FromResult(returnValue)); - this.decorator.GetFieldValue(ordinal).Should().Be(returnValue); + (await this.decorator.GetFieldValueAsync(ordinal, CancellationToken.None)).Should().Be(returnValue); - this.decoratedReader.Received().GetFieldValue(ordinal); + await this.decoratedReader.Received().GetFieldValueAsync(ordinal, CancellationToken.None); } [Fact] - public async Task GetFieldValueAsync_ShouldForwardToDecoratedReader() + public void GetFieldValue_ShouldForwardToDecoratedReader() { var ordinal = Generate.SmallNumber(); var returnValue = Generate.SmallNumber(); - this.decoratedReader.GetFieldValueAsync(ordinal, CancellationToken.None) - .Returns(Task.FromResult(returnValue)); + this.decoratedReader.GetFieldValue(ordinal).Returns(returnValue); - (await this.decorator.GetFieldValueAsync(ordinal, CancellationToken.None)).Should().Be(returnValue); + this.decorator.GetFieldValue(ordinal).Should().Be(returnValue); - await this.decoratedReader.Received().GetFieldValueAsync(ordinal, CancellationToken.None); + this.decoratedReader.Received().GetFieldValue(ordinal); } [Fact] @@ -100,9 +105,4 @@ public void ShouldGuardAgainstNullArguments() => CancellationToken.None ) ); - - private readonly DbCommandDisposer commandDisposer; - - private readonly DbDataReader decoratedReader; - private readonly CommandDisposingDataReaderDecorator decorator; } diff --git a/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderOptionsTests.cs b/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderOptionsTests.cs index 3d715fd..96943f2 100644 --- a/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderOptionsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderOptionsTests.cs @@ -100,6 +100,22 @@ public void GetString_EnumValuesSerialized_ShouldReturnEnumAsString() } } + [Fact] + public void GetValue_NullProperty_ShouldReturnDbNull() + { + Entity[] entities = [new() { StringValue = null! }]; + + using var reader = CreateReader(typeof(Entity), entities, EnumerableReaderOptions.None); + + reader.Read(); + + var ordinal = reader.GetOrdinal("StringValue"); + + reader.GetValue(ordinal).Should().Be(DBNull.Value); + + reader.IsDBNull(ordinal).Should().BeTrue(); + } + [Fact] public void GetValues_CharPropertyReadAsString_ShouldConvertToString() { @@ -183,22 +199,6 @@ public void GetValues_NoOptions_ShouldReturnRawEnumAndCharValues() values[reader.GetOrdinal("CharValue")].Should().Be(entity.CharValue); } - [Fact] - public void GetValue_NullProperty_ShouldReturnDbNull() - { - Entity[] entities = [new() { StringValue = null! }]; - - using var reader = CreateReader(typeof(Entity), entities, EnumerableReaderOptions.None); - - reader.Read(); - - var ordinal = reader.GetOrdinal("StringValue"); - - reader.GetValue(ordinal).Should().Be(DBNull.Value); - - reader.IsDBNull(ordinal).Should().BeTrue(); - } - /// /// Creates a multi-column reader over the mapped, readable properties of the specified entity type. /// diff --git a/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderTests.cs b/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderTests.cs index 8532ef2..4f12e76 100644 --- a/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Readers/EnumerableReaderTests.cs @@ -9,6 +9,11 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.Readers; public class EnumerableReaderTests : UnitTestsBase { + private const string FieldName = "Value"; + + private readonly EnumerableReader enumerableReader; + private readonly int[] testValues; + /// public EnumerableReaderTests() { @@ -17,17 +22,7 @@ public EnumerableReaderTests() } [Fact] - public void Close_ShouldCloseReader() - { - this.enumerableReader.IsClosed.Should().BeFalse(); - - this.enumerableReader.Close(); - - this.enumerableReader.IsClosed.Should().BeTrue(); - } - - [Fact] - public void Close_ShouldDisposeEnumerator() + public async Task CloseAsync_ShouldDisposeEnumerator() { var enumerable = Substitute.For(); var enumerator = Substitute.For(); @@ -36,13 +31,23 @@ public void Close_ShouldDisposeEnumerator() var reader = new EnumerableReader(enumerable, typeof(int), FieldName); - reader.Close(); + await reader.CloseAsync(); ((IDisposable)enumerator).Received().Dispose(); } [Fact] - public async Task CloseAsync_ShouldDisposeEnumerator() + public void Close_ShouldCloseReader() + { + this.enumerableReader.IsClosed.Should().BeFalse(); + + this.enumerableReader.Close(); + + this.enumerableReader.IsClosed.Should().BeTrue(); + } + + [Fact] + public void Close_ShouldDisposeEnumerator() { var enumerable = Substitute.For(); var enumerator = Substitute.For(); @@ -51,7 +56,7 @@ public async Task CloseAsync_ShouldDisposeEnumerator() var reader = new EnumerableReader(enumerable, typeof(int), FieldName); - await reader.CloseAsync(); + reader.Close(); ((IDisposable)enumerator).Received().Dispose(); } @@ -70,7 +75,7 @@ public void Constructor_FieldNameEmptyOrWhitespace_ShouldThrow() public void Depth_ShouldAlwaysReturnZero() => this.enumerableReader.Depth.Should().Be(0); [Fact] - public void Dispose_ShouldDisposeEnumerator() + public async Task DisposeAsync_ShouldDisposeEnumerator() { var enumerable = Substitute.For(); var enumerator = Substitute.For(); @@ -79,13 +84,13 @@ public void Dispose_ShouldDisposeEnumerator() var reader = new EnumerableReader(enumerable, typeof(int), FieldName); - reader.Dispose(); + await reader.DisposeAsync(); ((IDisposable)enumerator).Received().Dispose(); } [Fact] - public async Task DisposeAsync_ShouldDisposeEnumerator() + public void Dispose_ShouldDisposeEnumerator() { var enumerable = Substitute.For(); var enumerator = Substitute.For(); @@ -94,7 +99,7 @@ public async Task DisposeAsync_ShouldDisposeEnumerator() var reader = new EnumerableReader(enumerable, typeof(int), FieldName); - await reader.DisposeAsync(); + reader.Dispose(); ((IDisposable)enumerator).Received().Dispose(); } @@ -102,6 +107,32 @@ public async Task DisposeAsync_ShouldDisposeEnumerator() [Fact] public void FieldCount_ShouldAlwaysReturnOne() => this.enumerableReader.FieldCount.Should().Be(1); + [Fact] + public void Fields_MultiColumn_ShouldMatchMappedReadableProperties() + { + var properties = EntityHelper + .GetEntityTypeMetadata(typeof(Entity)) + .MappedProperties.Where(a => a.CanRead) + .ToArray(); + + using var reader = new EnumerableReader(new Entity[] { new() }, properties, EnumerableReaderOptions.None); + + reader.FieldCount.Should().Be(properties.Length); + + Enumerable + .Range(0, properties.Length) + .Select(reader.GetName) + .Should() + .Equal(properties.Select(a => a.PropertyName)); + + properties + .Select(a => reader.GetOrdinal(a.PropertyName)) + .Should() + .Equal(Enumerable.Range(0, properties.Length)); + + reader.GetOrdinal("NonExistentField").Should().Be(-1); + } + [Fact] public void GetDataTypeName_InvalidOrdinal_ShouldThrow() => Invoking(() => this.enumerableReader.GetDataTypeName(1)) @@ -199,6 +230,26 @@ public void GetValues_BufferTooSmall_ShouldThrow() .WithMessage("The specified array must have a length greater than or equal to 1.*"); } + [Fact] + public void GetValues_MultiColumnShortBuffer_ShouldFillAvailableEntries() + { + var entity = Generate.Single(); + var properties = EntityHelper + .GetEntityTypeMetadata(typeof(Entity)) + .MappedProperties.Where(a => a.CanRead) + .ToArray(); + + using var reader = new EnumerableReader(new[] { entity }, properties, EnumerableReaderOptions.None); + + reader.Read(); + + var values = new object[2]; + + reader.GetValues(values).Should().Be(values.Length); + + values.Should().Equal(properties.Take(values.Length).Select(a => a.PropertyGetter!(entity) ?? DBNull.Value)); + } + [Fact] public void GetValues_ShouldAlwaysReturnOne() { @@ -227,52 +278,6 @@ public void GetValues_ShouldFillBufferWithValue() } } - [Fact] - public void Fields_MultiColumn_ShouldMatchMappedReadableProperties() - { - var properties = EntityHelper - .GetEntityTypeMetadata(typeof(Entity)) - .MappedProperties.Where(a => a.CanRead) - .ToArray(); - - using var reader = new EnumerableReader(new Entity[] { new() }, properties, EnumerableReaderOptions.None); - - reader.FieldCount.Should().Be(properties.Length); - - Enumerable - .Range(0, properties.Length) - .Select(reader.GetName) - .Should() - .Equal(properties.Select(a => a.PropertyName)); - - properties - .Select(a => reader.GetOrdinal(a.PropertyName)) - .Should() - .Equal(Enumerable.Range(0, properties.Length)); - - reader.GetOrdinal("NonExistentField").Should().Be(-1); - } - - [Fact] - public void GetValues_MultiColumnShortBuffer_ShouldFillAvailableEntries() - { - var entity = Generate.Single(); - var properties = EntityHelper - .GetEntityTypeMetadata(typeof(Entity)) - .MappedProperties.Where(a => a.CanRead) - .ToArray(); - - using var reader = new EnumerableReader(new[] { entity }, properties, EnumerableReaderOptions.None); - - reader.Read(); - - var values = new object[2]; - - reader.GetValues(values).Should().Be(values.Length); - - values.Should().Equal(properties.Take(values.Length).Select(a => a.PropertyGetter!(entity) ?? DBNull.Value)); - } - [Fact] public void HasRows_ShouldAlwaysReturnTrue() => this.enumerableReader.HasRows.Should().BeTrue(); @@ -401,8 +406,4 @@ Func accessor accessor(reader).Should().Be(value); } - - private readonly EnumerableReader enumerableReader; - private readonly int[] testValues; - private const string FieldName = "Value"; } diff --git a/tests/DbConnectionPlus.UnitTests/StatementMethodTestsBase.cs b/tests/DbConnectionPlus.UnitTests/StatementMethodTestsBase.cs index 19664db..1a5995d 100644 --- a/tests/DbConnectionPlus.UnitTests/StatementMethodTestsBase.cs +++ b/tests/DbConnectionPlus.UnitTests/StatementMethodTestsBase.cs @@ -29,6 +29,25 @@ public abstract class StatementMethodTestsBase( > syncTestMethod ) : UnitTestsBase { + private readonly Func< + DbConnection, + InterpolatedSqlStatement, + DbTransaction?, + TimeSpan?, + CommandType, + CancellationToken, + Task + > asyncTestMethod = asyncTestMethod; + + private readonly Action< + DbConnection, + InterpolatedSqlStatement, + DbTransaction?, + TimeSpan?, + CommandType, + CancellationToken + > syncTestMethod = syncTestMethod; + [Fact] public async Task AsyncMethod_ShouldUseCommandTimeout() { @@ -150,23 +169,4 @@ public void SyncMethod_ShouldUseTransaction() Arg.Any>() ); } - - private readonly Func< - DbConnection, - InterpolatedSqlStatement, - DbTransaction?, - TimeSpan?, - CommandType, - CancellationToken, - Task - > asyncTestMethod = asyncTestMethod; - - private readonly Action< - DbConnection, - InterpolatedSqlStatement, - DbTransaction?, - TimeSpan?, - CommandType, - CancellationToken - > syncTestMethod = syncTestMethod; } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/Entity.cs b/tests/DbConnectionPlus.UnitTests/TestData/Entity.cs index be02316..c94281e 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/Entity.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/Entity.cs @@ -3,8 +3,8 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public record Entity { public bool BooleanValue { get; set; } - public byte[] BytesValue { get; set; } = null!; public byte ByteValue { get; set; } + public byte[] BytesValue { get; set; } = null!; public char CharValue { get; set; } public DateOnly DateOnlyValue { get; set; } public DateTime DateTimeValue { get; set; } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithDifferentCasingProperties.cs b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithDifferentCasingProperties.cs index ba1df09..9952410 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithDifferentCasingProperties.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithDifferentCasingProperties.cs @@ -5,8 +5,8 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public record EntityWithDifferentCasingProperties { public bool BooleanVALUE { get; set; } - public byte[] BytesVALUE { get; set; } = null!; public byte ByteVALUE { get; set; } + public byte[] BytesVALUE { get; set; } = null!; public char CharVALUE { get; set; } public DateOnly DateOnlyVALUE { get; set; } public DateTime DateTimeVALUE { get; set; } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionA.cs b/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionA.cs index e6aaf60..1f0c7af 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionA.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionA.cs @@ -5,21 +5,21 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public class FakeConnectionA : DbConnection { /// - [AllowNull] - public override string ConnectionString { get; set; } + public override string DataSource => null!; /// public override string Database => null!; - /// - public override string DataSource => null!; - /// public override string ServerVersion => null!; /// public override ConnectionState State => ConnectionState.Closed; + /// + [AllowNull] + public override string ConnectionString { get; set; } + /// public override void ChangeDatabase(string databaseName) => throw new NotImplementedException(); diff --git a/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionB.cs b/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionB.cs index b140e98..c1f6eea 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionB.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionB.cs @@ -5,21 +5,21 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public class FakeConnectionB : DbConnection { /// - [AllowNull] - public override string ConnectionString { get; set; } + public override string DataSource => null!; /// public override string Database => null!; - /// - public override string DataSource => null!; - /// public override string ServerVersion => null!; /// public override ConnectionState State => ConnectionState.Closed; + /// + [AllowNull] + public override string ConnectionString { get; set; } + /// public override void ChangeDatabase(string databaseName) => throw new NotImplementedException(); diff --git a/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionC.cs b/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionC.cs index 907751d..a941f03 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionC.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/FakeConnectionC.cs @@ -5,21 +5,21 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public class FakeConnectionC : FakeConnectionA { /// - [AllowNull] - public override string ConnectionString { get; set; } + public override string DataSource => null!; /// public override string Database => null!; - /// - public override string DataSource => null!; - /// public override string ServerVersion => null!; /// public override ConnectionState State => ConnectionState.Closed; + /// + [AllowNull] + public override string ConnectionString { get; set; } + /// public override void ChangeDatabase(string databaseName) => throw new NotImplementedException(); diff --git a/tests/DbConnectionPlus.UnitTests/TestData/Generate.cs b/tests/DbConnectionPlus.UnitTests/TestData/Generate.cs index 46c870b..83ff74c 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/Generate.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/Generate.cs @@ -17,6 +17,17 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; /// public static class Generate { + /// + /// The characters used for Char generation. + /// We only use alphabetic characters for Char generation to avoid issues with databases that do not support + /// certain characters. + /// + private static readonly char[] characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray(); + + private static readonly Faker faker; + private static readonly Fixture fixture; + private static long entityId = 1; + /// /// Initializes the class. /// @@ -298,17 +309,6 @@ private static void CopyKeysAndConcurrencyTokens(T sourceEntity, T targetEnti } } - /// - /// The characters used for Char generation. - /// We only use alphabetic characters for Char generation to avoid issues with databases that do not support - /// certain characters. - /// - private static readonly char[] characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray(); - - private static readonly Faker faker; - private static readonly Fixture fixture; - private static long entityId = 1; - /// /// An AutoFixture customization that excludes properties that are ignored in the entity model from being populated /// with test data. diff --git a/tests/DbConnectionPlus.UnitTests/TestData/NotAValueTuple.cs b/tests/DbConnectionPlus.UnitTests/TestData/NotAValueTuple.cs index e7d8304..8cfa2a5 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/NotAValueTuple.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/NotAValueTuple.cs @@ -6,10 +6,10 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; public struct NotAValueTuple : IStructuralEquatable, IStructuralComparable, IComparable { /// - public int CompareTo(object? other, IComparer comparer) => throw new NotImplementedException(); + public int CompareTo(object? obj) => throw new NotImplementedException(); /// - public int CompareTo(object? obj) => throw new NotImplementedException(); + public int CompareTo(object? other, IComparer comparer) => throw new NotImplementedException(); /// public bool Equals(object? other, IEqualityComparer comparer) => throw new NotImplementedException(); diff --git a/tests/DbConnectionPlus.UnitTests/Trimming/ILLinkDescriptorsTests.cs b/tests/DbConnectionPlus.UnitTests/Trimming/ILLinkDescriptorsTests.cs index ca0078d..95e126e 100644 --- a/tests/DbConnectionPlus.UnitTests/Trimming/ILLinkDescriptorsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Trimming/ILLinkDescriptorsTests.cs @@ -22,6 +22,8 @@ namespace RentADeveloper.DbConnectionPlus.UnitTests.Trimming; /// public class ILLinkDescriptorsTests : UnitTestsBase { + private const string ILLinkDescriptorsResourceName = "ILLink.Descriptors.xml"; + [Fact] public void CoreAssembly_ShouldEmbedTheILLinkDescriptor() => typeof(DbConnectionExtensions) @@ -57,6 +59,4 @@ private static XDocument ReadDescriptor() return XDocument.Load(stream); } - - private const string ILLinkDescriptorsResourceName = "ILLink.Descriptors.xml"; } From 14430156b05bd8ef1c1fe7c6bacf7c2aa5373c86 Mon Sep 17 00:00:00 2001 From: David Liebeherr Date: Thu, 27 Aug 2026 06:58:01 +0200 Subject: [PATCH 08/12] build: the file layout, and the remaining analyzer gates Explicit interface implementations get their own file layout entry per kind (property, indexer, method), matching ImplementsInterface AND Access Is=Private. Without the access test the entry also catches implicit implementations and drags Equals(T) away from Equals(object). Events must NOT have one: StyleCop counts an explicit event as private, and giving it an entry breaks the build. Four gates added: IDE0005 unused using. Needs GenerateDocumentationFile on every project, or it is never reported at build time (dotnet/roslyn#41640). RCS1250 target-typed new, where IDE0090 cannot reach - return, argument and assignment positions. SA1208/9/10/11/17 using order. These check rather than fix: CSharpier already sorts usings. SA1216 is excluded because CSharpier contradicts it. CSharpier.MsBuild an unformatted file becomes a build error, in check mode so the build never rewrites sources. The code catches up in the next commit. Part of #21 Co-Authored-By: Claude Opus 5 --- .config/dotnet-tools.json | 2 +- .editorconfig | 133 +++++++--- DbConnectionPlus.slnx.DotSettings | 409 +++++++++++++++++------------- Directory.Build.props | 52 ++-- 4 files changed, 365 insertions(+), 231 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index bfcc8ba..a47c819 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -24,4 +24,4 @@ "rollForward": false } } -} \ No newline at end of file +} diff --git a/.editorconfig b/.editorconfig index 1eeab81..8fbb815 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,26 +15,17 @@ indent_size = 4 insert_final_newline = true trim_trailing_whitespace = true -# MSBuild and ReSharper settings files are tab-indented, which is what is already in the repository. [*.{csproj,props,targets,DotSettings}] indent_style = tab tab_width = 4 -# The solution file, the NuGet configs and the trimmer descriptor use two spaces, also matching what is -# already there. -[*.{slnx,config,xml}] -indent_size = 2 - -[*.{json,yml,yaml}] +[*.{slnx,config,xml,json,yml,yaml}] indent_size = 2 # Two trailing spaces are a hard line break in Markdown, so they must survive. [*.md] trim_trailing_whitespace = false -[*.ps1] -end_of_line = crlf - # ====================================================================================================== # C# # @@ -71,8 +62,11 @@ csharp_style_var_when_type_is_apparent = true:error #### Member access: always `this.` #### # Instance members are always read and written through `this.`, and fields are never `_camelCase`. -# Primary constructor parameters are the one thing this does not cover, and that is not an exception: -# in C# they are parameters, not instance members, so `this.` cannot be applied to them at all. +# +# A primary constructor parameter is assigned to a `private readonly` backing field and read through +# `this.field`, never used directly in a member body. Nothing below enforces that - a parameter is not an +# instance member, so these four rules cannot see it - but a captured parameter compiles to a field with no +# `readonly`, and using one directly would silently drop the guarantee that it cannot be reassigned. dotnet_style_qualification_for_event = true:error dotnet_style_qualification_for_field = true:error dotnet_style_qualification_for_method = true:error @@ -93,6 +87,10 @@ csharp_style_prefer_simple_property_accessors = true:error #### Namespaces and using directives #### +# An unused using is a build error. This needs the documentation file that Directory.Build.props turns +# on for every project - without one, IDE0005 is simply never reported at build time. +dotnet_diagnostic.IDE0005.severity = error + csharp_style_namespace_declarations = file_scoped:error csharp_using_directive_placement = outside_namespace:error dotnet_style_namespace_match_folder = true:error @@ -109,7 +107,17 @@ dotnet_style_prefer_auto_properties = true:error csharp_prefer_simple_default_expression = true:error csharp_prefer_simple_using_statement = true:suggestion csharp_prefer_system_threading_lock = false:silent +# `new()` wherever the compiler can infer the type. IDE0090 covers only the case where the type is +# written next to it - `EnumerableReader r = new EnumerableReader(...)` - which the `var` rule above +# makes impossible anyway, so on its own it has almost nothing to fire on here. +# +# RCS1250 covers what IDE0090 does not: `return new T(...)`, an argument, and an assignment to an +# already-typed target. Not everything - it stays quiet on a `new` nested inside another `new` that is +# itself an argument, as in EntityMaterializerFactory's propertyBindings.Add(...). Rider flags those; +# the build does not, so they are on the author. csharp_style_implicit_object_creation_when_type_is_apparent = true:error +roslynator_object_creation_type_style = implicit +dotnet_diagnostic.RCS1250.severity = error csharp_style_inlined_variable_declaration = true:error csharp_style_prefer_implicitly_typed_lambda_expression = true:error csharp_style_prefer_index_operator = true:error @@ -226,29 +234,60 @@ dotnet_analyzer_diagnostic.category-StyleCop.CSharp.ReadabilityRules.severity = dotnet_analyzer_diagnostic.category-StyleCop.CSharp.SpacingRules.severity = none dotnet_analyzer_diagnostic.category-StyleCop.CSharp.SpecialRules.severity = none +# SA1208, SA1209, SA1210, SA1211, SA1217: the order of using directives. +# +# CSharpier already sorts using directives, so these five do not fix anything - they CHECK that what +# CSharpier produced is what we want, and catch a file that reached the repository without it. All five +# report zero violations across the 283 files, which is what says CSharpier and StyleCop agree here. +# +# SA1208 is also what makes `systemUsingDirectivesFirst` in stylecop.json mean something. With the rule +# off, that setting was read by nothing. +# +# SA1216 (using static placed after the regular usings) is deliberately ABSENT: it is the one CSharpier +# contradicts. CSharpier sorts by namespace and ignores the `static` keyword, so it writes +# +# global using AwesomeAssertions; +# global using static AwesomeAssertions.FluentActions; +# global using Microsoft.Data.SqlClient; +# +# where SA1216 wants both `using static` lines grouped at the end. Enabling it makes the build +# unsatisfiable, because CSharpier runs last and always has the final say - verified by sorting the file +# StyleCop's way and watching CSharpier put it straight back. +# +# SA1200 is absent for a different reason: `csharp_using_directive_placement` above already requires +# usings outside the namespace, and two rules for one decision is how they end up disagreeing. +dotnet_diagnostic.SA1208.severity = error +dotnet_diagnostic.SA1209.severity = error +dotnet_diagnostic.SA1210.severity = error +dotnet_diagnostic.SA1211.severity = error +dotnet_diagnostic.SA1217.severity = error + # SA1201: Elements should appear in the correct order (by kind). dotnet_diagnostic.SA1201.severity = error -# SA1202: Elements should be ordered by access. OFF, and this is the one place where the checker and the -# fixer genuinely disagree. +# SA1202: Elements should be ordered by access. +# +# Explicit interface implementations need a word, because the checker and the fixer classify them +# differently. ReSharper ranks one below private, since in C# it carries no access modifier, so left +# alone it lands at the bottom of its kind group. # -# The two tools classify an explicit interface implementation differently. StyleCop counts -# `void IFreezable.Freeze()` as public; ReSharper sorts it with the private members, because in C# it -# carries no access modifier. So ReSharper puts it last inside its kind group and StyleCop then reports -# a public member sitting after a private one - on four members here, and on every explicit interface -# implementation anyone writes from now on. +# StyleCop disagrees, but NOT uniformly - which is why the file layout has one entry per kind rather +# than one shared entry: # -# There is no setting that reconciles them. Sorting interface members first in the file layout does not -# do it (ReSharper sorts them last, not first) and it separates the Equals overloads, which trips Sonar's -# S4136. That leaves a rule the fixer cannot satisfy: scripts/tidy-cs.ps1 would produce code the build -# rejects, and the next run would produce the same code again. A rule nothing can fix is worse than no -# rule, so it is off. +# properties, indexers, methods counted as public, so they must come FIRST in their group. +# The layout has an "Explicit interface " entry for each. +# events counted as private, so ReSharper's default placement is already +# right. Giving events an entry actively breaks the build - it puts +# the explicit event ahead of a public one, which is SA1202. # -# What is lost: accessibility order is still APPLIED - the file layout in the .DotSettings sorts by access -# before anything else - it is just not VERIFIED by the build. Kind order (SA1201), constants (SA1203), -# static (SA1204) and readonly (SA1214) are all still checked, and all four keep accessibility as their -# higher-priority trait, so they only pass if the accessibility order is right anyway. -dotnet_diagnostic.SA1202.severity = none +# The entries match on ImplementsInterface AND Access Is="Private", and both halves matter. +# ImplementsInterface on its own also matches IMPLICIT implementations, which drags Equals(T) away +# from Equals(object) and trips Sonar's S4136. An implicit implementation has to be public, so the +# access test is what narrows each entry to the explicit ones. +# +# One shared entry across the kinds would not work either: it would sit an explicit property next to +# an explicit method and break SA1201's kind order. +dotnet_diagnostic.SA1202.severity = error # SA1203: Constants should appear before fields. dotnet_diagnostic.SA1203.severity = error @@ -333,20 +372,54 @@ dotnet_diagnostic.xUnit1051.severity = none # Tests and benchmarks # # Held to the same style, formatting and ordering as the shipping libraries. What they are NOT held to is -# a handful of Sonar rules that only make sense for library code. +# XML documentation, and a handful of Sonar rules that only make sense for library code. # ====================================================================================================== [{tests,benchmarks}/**/*.cs] +# CS1591: Missing XML comment for publicly visible type or member +# CS1574: XML comment has a cref attribute that could not be resolved +# +# Every project generates a documentation file, because IDE0005 does not work without one - see the +# comment in Directory.Build.props. That switches these two compiler diagnostics on everywhere as a side +# effect, and with TreatWarningsAsErrors they are 3202 errors here. Nothing consumes the tests or the +# benchmarks as an API and they use plain `//` comments by design, so both are off for them. In src/ they +# stay errors, which is what actually keeps the public API documented. +dotnet_diagnostic.CS1574.severity = none +dotnet_diagnostic.CS1591.severity = none + +# S1144: Unused private types or members should be removed dotnet_diagnostic.S1144.severity = none + +# S1172: Unused method parameters should be removed dotnet_diagnostic.S1172.severity = none + +# S2344: Enumeration type names should not have "Flags" or "Enum" suffixes dotnet_diagnostic.S2344.severity = none + +# S2696: Instance members should not write to "static" fields dotnet_diagnostic.S2696.severity = none + +# S2925: "Thread.Sleep" should not be used in tests dotnet_diagnostic.S2925.severity = none + +# S3010: Static fields should not be updated in constructors dotnet_diagnostic.S3010.severity = none + +# S3453: Classes should not have only "private" constructors dotnet_diagnostic.S3453.severity = none + +# S3459: Unassigned members should be removed dotnet_diagnostic.S3459.severity = none + +# S3963: "static" fields should be initialized inline dotnet_diagnostic.S3963.severity = none + +# S4144: Methods should not have identical implementations dotnet_diagnostic.S4144.severity = none + +# S5034: "ValueTask" should be consumed correctly dotnet_diagnostic.S5034.severity = none + +# S6562: Always set the "DateTimeKind" when creating new "DateTime" instances dotnet_diagnostic.S6562.severity = none diff --git a/DbConnectionPlus.slnx.DotSettings b/DbConnectionPlus.slnx.DotSettings index ac70d55..54a5ad3 100644 --- a/DbConnectionPlus.slnx.DotSettings +++ b/DbConnectionPlus.slnx.DotSettings @@ -1,184 +1,229 @@ - - <?xml version="1.0" encoding="utf-16"?> -<Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"> - <TypePattern DisplayName="Types marked [NoReorder]" Priority="100"> - <TypePattern.Match> - <HasAttribute Name="JetBrains.Annotations.NoReorderAttribute" /> - </TypePattern.Match> - </TypePattern> - <TypePattern DisplayName="StyleCop order" RemoveRegions="None"> - <Entry DisplayName="Constants"> - <Entry.Match> - <Kind Is="Constant" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> - <Static /> - <Readonly /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Fields"> - <Entry.Match> - <Kind Is="Field" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> - <Static /> - <Readonly /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Constructors"> - <Entry.Match> - <Kind Is="Constructor" /> - </Entry.Match> - <Entry.SortBy> - <Static /> - <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> - <Readonly /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Finalizers"> - <Entry.Match> - <Kind Is="Destructor" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> - <Static /> - <Readonly /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Delegates"> - <Entry.Match> - <Kind Is="Delegate" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> - <Static /> - <Readonly /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Events"> - <Entry.Match> - <Kind Is="Event" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> - <Static /> - <Readonly /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Enums"> - <Entry.Match> - <Kind Is="Enum" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> - <Static /> - <Readonly /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Interfaces"> - <Entry.Match> - <Kind Is="Interface" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> - <Static /> - <Readonly /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Properties"> - <Entry.Match> - <Kind Is="Property" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> - <Static /> - <Readonly /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Indexers"> - <Entry.Match> - <Kind Is="Indexer" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> - <Static /> - <Readonly /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Conversion operators"> - <Entry.Match> - <And> - <Kind Is="Operator" /> - <Or> - <Name Is="op_Implicit" /> - <Name Is="op_Explicit" /> - </Or> - </And> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> - <Static /> - <Readonly /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Operators"> - <Entry.Match> - <Kind Is="Operator" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> - <Static /> - <Readonly /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Methods"> - <Entry.Match> - <Kind Is="Method" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> - <Static /> - <Readonly /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Structs"> - <Entry.Match> - <Kind Is="Struct" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> - <Static /> - <Readonly /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Classes"> - <Entry.Match> - <Kind Is="Class" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> - <Static /> - <Readonly /> - <Name /> - </Entry.SortBy> - </Entry> - </TypePattern> + + <?xml version="1.0" encoding="utf-16"?> +<Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"> + <TypePattern DisplayName="Types marked [NoReorder]" Priority="100"> + <TypePattern.Match> + <HasAttribute Name="JetBrains.Annotations.NoReorderAttribute" /> + </TypePattern.Match> + </TypePattern> + <TypePattern DisplayName="StyleCop order" RemoveRegions="None"> + <Entry DisplayName="Constants"> + <Entry.Match> + <Kind Is="Constant" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Fields"> + <Entry.Match> + <Kind Is="Field" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Constructors"> + <Entry.Match> + <Kind Is="Constructor" /> + </Entry.Match> + <Entry.SortBy> + <Static /> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Finalizers"> + <Entry.Match> + <Kind Is="Destructor" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Delegates"> + <Entry.Match> + <Kind Is="Delegate" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Events"> + <Entry.Match> + <Kind Is="Event" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Enums"> + <Entry.Match> + <Kind Is="Enum" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Interfaces"> + <Entry.Match> + <Kind Is="Interface" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Explicit interface properties"> + <Entry.Match> + <And> + <Kind Is="Property" /> + <ImplementsInterface /> + <Access Is="Private" /> + </And> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Properties"> + <Entry.Match> + <Kind Is="Property" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Explicit interface indexers"> + <Entry.Match> + <And> + <Kind Is="Indexer" /> + <ImplementsInterface /> + <Access Is="Private" /> + </And> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Indexers"> + <Entry.Match> + <Kind Is="Indexer" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Conversion operators"> + <Entry.Match> + <And> + <Kind Is="Operator" /> + <Or> + <Name Is="op_Implicit" /> + <Name Is="op_Explicit" /> + </Or> + </And> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Operators"> + <Entry.Match> + <Kind Is="Operator" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Explicit interface methods"> + <Entry.Match> + <And> + <Kind Is="Method" /> + <ImplementsInterface /> + <Access Is="Private" /> + </And> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Methods"> + <Entry.Match> + <Kind Is="Method" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Structs"> + <Entry.Match> + <Kind Is="Struct" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Classes"> + <Entry.Match> + <Kind Is="Class" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected PrivateProtected Private" /> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + </TypePattern> </Patterns> <?xml version="1.0" encoding="utf-16"?><Profile name="ReorderMembers"><CSReorderTypeMembers>True</CSReorderTypeMembers></Profile> True @@ -207,4 +252,4 @@ True True True - True \ No newline at end of file + True diff --git a/Directory.Build.props b/Directory.Build.props index 36ad4a1..cfc2df9 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -24,30 +24,37 @@ - - True - true + true + + - $(NoWarn);SA0001 + true @@ -55,6 +62,15 @@ The style analyzers every project is held to. They are PrivateAssets=all, so they never flow to a consumer of the packages. --> + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + all runtime; build; native; contentfiles; analyzers; buildtransitive From 70f9ea67d055d9932c1ff9f5bf3204af9e1c78c4 Mon Sep 17 00:00:00 2001 From: David Liebeherr Date: Thu, 27 Aug 2026 06:58:02 +0200 Subject: [PATCH 09/12] style: satisfy the gates the previous commit turned on Mostly tool output: 20 unused using directives removed dotnet format style, IDE0005 14 object creations to target-typed new dotnet format analyzers, RCS1250 7 files reordered jb cleanupcode, after the layout gained the explicit-interface entries By hand, where no tool reaches: IDE0049 misses nint/nuint, never looks inside nameof(), and never sees tests/package-consumption/ because it is not in the solution. Converted there. MySqlEntityManipulator was the last adapter on a classic constructor, hidden behind a stale #pragma warning disable IDE0290. Two global using Xunit lines the SDK already generates. Redundant rather than unused, so IDE0005 correctly stays quiet. Two Query test lambdas keep an explicit .ToList(): the lambda is an Action, so its body must be a statement and a collection expression is not one (CS0201). Part of #21 Co-Authored-By: Claude Opus 5 --- .../TestData/Generate.cs | 2 - .../GlobalUsings.cs | 1 - .../MySqlConfigurationExtensions.cs | 1 + .../MySqlEntityManipulator.cs | 13 ++----- .../MySqlTemporaryTableBuilder.cs | 17 ++------- .../GlobalUsings.cs | 1 - .../OracleConfigurationExtensions.cs | 1 + .../OracleEntityManipulator.cs | 3 +- .../OracleTemporaryTableBuilder.cs | 5 +-- .../GlobalUsings.cs | 1 - .../PostgreSqlConfigurationExtensions.cs | 1 + .../PostgreSqlEntityManipulator.cs | 1 - .../PostgreSqlTemporaryTableBuilder.cs | 5 +-- .../GlobalUsings.cs | 1 - .../SqlServerConfigurationExtensions.cs | 1 + .../SqlServerEntityManipulator.cs | 1 - .../SqlServerTemporaryTableBuilder.cs | 5 +-- .../GlobalUsings.cs | 1 - .../SqliteConfigurationExtensions.cs | 1 + .../SqliteEntityManipulator.cs | 1 - .../SqliteTemporaryTableBuilder.cs | 5 +-- .../DbConnectionPlusConfiguration.cs | 22 +++++------ .../Configuration/EntityPropertyBuilder.cs | 6 +-- .../Configuration/EntityTypeBuilder.cs | 22 +++++------ .../Converters/EnumConverter.cs | 1 - .../Converters/ValueConverter.cs | 5 +-- .../DbConnectionExtensions.Configuration.cs | 1 - src/DbConnectionPlus/Dynamic/DataRow.cs | 15 +++++--- .../Extensions/ObjectExtensions.cs | 4 +- .../Extensions/TypeExtensions.cs | 4 +- .../EntityMaterializerFactory.cs | 28 +++++++------- .../MaterializerFactoryHelper.cs | 4 +- .../ValueTupleMaterializerFactory.cs | 8 ++-- .../Readers/EnumerableReader.cs | 20 +++++----- .../SqlStatements/InterpolatedSqlStatement.cs | 4 +- src/DbConnectionPlus/ThrowHelper.cs | 1 - .../GlobalUsings.cs | 1 - .../Converters/ValueConverterTests.cs | 16 ++++---- .../DbConnectionExtensions.QueryOfTTests.cs | 5 +++ .../DbConnectionExtensions.QueryTests.cs | 5 +++ .../Extensions/ObjectExtensionsTests.cs | 6 +-- .../Extensions/TypeExtensionsTests.cs | 8 ++-- .../GlobalUsings.cs | 1 - .../MaterializerFactoryHelperTests.cs | 4 +- .../TestData/EntityWithPublicConstructor.cs | 2 + .../TestData/Generate.cs | 22 +++++------ .../TestData/ItemWithConstructor.cs | 2 + .../AllAdaptersConsumer/Program.cs | 12 +++--- .../package-consumption/AotConsumer/Model.cs | 22 +++++------ .../AotConsumer/Program.cs | 6 +-- .../AotConsumer/SmokeCases.cs | 38 +++++++++---------- tests/package-consumption/Check.cs | 22 +++++------ 52 files changed, 184 insertions(+), 201 deletions(-) diff --git a/benchmarks/DbConnectionPlus.Benchmarks/TestData/Generate.cs b/benchmarks/DbConnectionPlus.Benchmarks/TestData/Generate.cs index 127a846..10e2d98 100644 --- a/benchmarks/DbConnectionPlus.Benchmarks/TestData/Generate.cs +++ b/benchmarks/DbConnectionPlus.Benchmarks/TestData/Generate.cs @@ -1,5 +1,3 @@ -using System.Globalization; - namespace RentADeveloper.DbConnectionPlus.Benchmarks.TestData; // Generates the entities the benchmarks operate on. A plain seeded generator rather than the unit test diff --git a/src/DbConnectionPlus.DatabaseAdapters.MySql/GlobalUsings.cs b/src/DbConnectionPlus.DatabaseAdapters.MySql/GlobalUsings.cs index cfc88dd..61f5ddc 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.MySql/GlobalUsings.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.MySql/GlobalUsings.cs @@ -4,5 +4,4 @@ global using System.Data.Common; global using System.Diagnostics.CodeAnalysis; global using RentADeveloper.DbConnectionPlus.Configuration; -global using RentADeveloper.DbConnectionPlus.DatabaseAdapters; global using RentADeveloper.DbConnectionPlus.Entities; diff --git a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlConfigurationExtensions.cs b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlConfigurationExtensions.cs index 4873dad..9033a63 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlConfigurationExtensions.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlConfigurationExtensions.cs @@ -2,6 +2,7 @@ using RentADeveloper.DbConnectionPlus.DatabaseAdapters.MySql; #pragma warning disable IDE0130 +// ReSharper disable once CheckNamespace namespace RentADeveloper.DbConnectionPlus.Configuration; #pragma warning restore IDE0130 diff --git a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlEntityManipulator.cs index b1a62fb..743ce34 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlEntityManipulator.cs @@ -4,26 +4,19 @@ using LinkDotNet.StringBuilder; using RentADeveloper.DbConnectionPlus.Converters; using RentADeveloper.DbConnectionPlus.DbCommands; -using RentADeveloper.DbConnectionPlus.Entities; namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.MySql; /// /// The entity manipulator for MySQL. /// -internal class MySqlEntityManipulator : IEntityManipulator +/// The database adapter to use to manipulate entities. +internal class MySqlEntityManipulator(MySqlDatabaseAdapter databaseAdapter) : IEntityManipulator { - private readonly MySqlDatabaseAdapter databaseAdapter; + private readonly MySqlDatabaseAdapter databaseAdapter = databaseAdapter; private readonly ConcurrentDictionary entityDeleteSqlCodePerEntityType = new(); private readonly ConcurrentDictionary entityInsertSqlCodePerEntityType = new(); private readonly ConcurrentDictionary entityUpdateSqlCodePerEntityType = new(); - /// - /// Initializes a new instance of the class. - /// - /// The database adapter to use to manipulate entities. -#pragma warning disable IDE0290 // Use primary constructor - public MySqlEntityManipulator(MySqlDatabaseAdapter databaseAdapter) => this.databaseAdapter = databaseAdapter; -#pragma warning restore IDE0290 // Use primary constructor /// public int DeleteEntities<[DynamicallyAccessedMembers(EntityHelper.EntityMemberTypes)] TEntity>( diff --git a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlTemporaryTableBuilder.cs b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlTemporaryTableBuilder.cs index 66386ec..98c0205 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlTemporaryTableBuilder.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.MySql/MySqlTemporaryTableBuilder.cs @@ -5,7 +5,6 @@ using MySqlConnector; using RentADeveloper.DbConnectionPlus.Converters; using RentADeveloper.DbConnectionPlus.DbCommands; -using RentADeveloper.DbConnectionPlus.Entities; using RentADeveloper.DbConnectionPlus.Extensions; using RentADeveloper.DbConnectionPlus.Readers; @@ -291,18 +290,10 @@ private static EnumerableReader CreateValuesDataReader( switch (DbConnectionPlusConfiguration.Instance.EnumSerializationMode) { case EnumSerializationMode.Integers: - return new EnumerableReader( - enumValues, - typeof(int?), - Constants.SingleColumnTemporaryTableColumnName - ); + return new(enumValues, typeof(int?), Constants.SingleColumnTemporaryTableColumnName); case EnumSerializationMode.Strings: - return new EnumerableReader( - enumValues, - typeof(string), - Constants.SingleColumnTemporaryTableColumnName - ); + return new(enumValues, typeof(string), Constants.SingleColumnTemporaryTableColumnName); default: return ThrowHelper.ThrowInvalidEnumSerializationModeException( @@ -311,10 +302,10 @@ private static EnumerableReader CreateValuesDataReader( } } - return new EnumerableReader(values, valuesType, Constants.SingleColumnTemporaryTableColumnName); + return new(values, valuesType, Constants.SingleColumnTemporaryTableColumnName); } - return new EnumerableReader( + return new( values, [.. EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a.CanRead)], EnumerableReaderOptions.SerializeEnums | EnumerableReaderOptions.ReadCharsAsStrings diff --git a/src/DbConnectionPlus.DatabaseAdapters.Oracle/GlobalUsings.cs b/src/DbConnectionPlus.DatabaseAdapters.Oracle/GlobalUsings.cs index cfc88dd..61f5ddc 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Oracle/GlobalUsings.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Oracle/GlobalUsings.cs @@ -4,5 +4,4 @@ global using System.Data.Common; global using System.Diagnostics.CodeAnalysis; global using RentADeveloper.DbConnectionPlus.Configuration; -global using RentADeveloper.DbConnectionPlus.DatabaseAdapters; global using RentADeveloper.DbConnectionPlus.Entities; diff --git a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleConfigurationExtensions.cs b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleConfigurationExtensions.cs index fbfc0c4..9c548ea 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleConfigurationExtensions.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleConfigurationExtensions.cs @@ -2,6 +2,7 @@ using RentADeveloper.DbConnectionPlus.DatabaseAdapters.Oracle; #pragma warning disable IDE0130 +// ReSharper disable once CheckNamespace namespace RentADeveloper.DbConnectionPlus.Configuration; #pragma warning restore IDE0130 diff --git a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleEntityManipulator.cs index 07a45af..33d34b9 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleEntityManipulator.cs @@ -4,12 +4,11 @@ using LinkDotNet.StringBuilder; using RentADeveloper.DbConnectionPlus.Converters; using RentADeveloper.DbConnectionPlus.DbCommands; -using RentADeveloper.DbConnectionPlus.Entities; namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.Oracle; /// -/// The entity manipulator for PostgreSQL. +/// The entity manipulator for Oracle. /// /// The database adapter to use to manipulate entities. internal class OracleEntityManipulator(OracleDatabaseAdapter databaseAdapter) : IEntityManipulator diff --git a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleTemporaryTableBuilder.cs b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleTemporaryTableBuilder.cs index b4c04f0..fd7c034 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleTemporaryTableBuilder.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Oracle/OracleTemporaryTableBuilder.cs @@ -4,7 +4,6 @@ using LinkDotNet.StringBuilder; using Oracle.ManagedDataAccess.Client; using RentADeveloper.DbConnectionPlus.DbCommands; -using RentADeveloper.DbConnectionPlus.Entities; using RentADeveloper.DbConnectionPlus.Extensions; using RentADeveloper.DbConnectionPlus.Readers; @@ -323,10 +322,10 @@ private static EnumerableReader CreateValuesDataReader( { if (valuesType.IsBuiltInTypeOrNullableBuiltInType() || valuesType.IsEnumOrNullableEnumType()) { - return new EnumerableReader(values, valuesType, Constants.SingleColumnTemporaryTableColumnName); + return new(values, valuesType, Constants.SingleColumnTemporaryTableColumnName); } - return new EnumerableReader( + return new( values, [.. EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a.CanRead)], EnumerableReaderOptions.None diff --git a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/GlobalUsings.cs b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/GlobalUsings.cs index cfc88dd..61f5ddc 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/GlobalUsings.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/GlobalUsings.cs @@ -4,5 +4,4 @@ global using System.Data.Common; global using System.Diagnostics.CodeAnalysis; global using RentADeveloper.DbConnectionPlus.Configuration; -global using RentADeveloper.DbConnectionPlus.DatabaseAdapters; global using RentADeveloper.DbConnectionPlus.Entities; diff --git a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlConfigurationExtensions.cs b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlConfigurationExtensions.cs index f14be42..bd2f49d 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlConfigurationExtensions.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlConfigurationExtensions.cs @@ -2,6 +2,7 @@ using RentADeveloper.DbConnectionPlus.DatabaseAdapters.PostgreSql; #pragma warning disable IDE0130 +// ReSharper disable once CheckNamespace namespace RentADeveloper.DbConnectionPlus.Configuration; #pragma warning restore IDE0130 diff --git a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlEntityManipulator.cs index 92475af..51752c6 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlEntityManipulator.cs @@ -4,7 +4,6 @@ using LinkDotNet.StringBuilder; using RentADeveloper.DbConnectionPlus.Converters; using RentADeveloper.DbConnectionPlus.DbCommands; -using RentADeveloper.DbConnectionPlus.Entities; namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.PostgreSql; diff --git a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlTemporaryTableBuilder.cs b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlTemporaryTableBuilder.cs index de0644d..4f46cd4 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlTemporaryTableBuilder.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.PostgreSql/PostgreSqlTemporaryTableBuilder.cs @@ -6,7 +6,6 @@ using NpgsqlTypes; using RentADeveloper.DbConnectionPlus.Converters; using RentADeveloper.DbConnectionPlus.DbCommands; -using RentADeveloper.DbConnectionPlus.Entities; using RentADeveloper.DbConnectionPlus.Extensions; using RentADeveloper.DbConnectionPlus.Readers; @@ -209,10 +208,10 @@ private static EnumerableReader CreateValuesDataReader( { if (valuesType.IsBuiltInTypeOrNullableBuiltInType() || valuesType.IsEnumOrNullableEnumType()) { - return new EnumerableReader(values, valuesType, Constants.SingleColumnTemporaryTableColumnName); + return new(values, valuesType, Constants.SingleColumnTemporaryTableColumnName); } - return new EnumerableReader( + return new( values, [.. EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a.CanRead)], EnumerableReaderOptions.None diff --git a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/GlobalUsings.cs b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/GlobalUsings.cs index 33f6f8e..e20940e 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/GlobalUsings.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/GlobalUsings.cs @@ -5,5 +5,4 @@ global using System.Diagnostics.CodeAnalysis; global using Microsoft.Data.SqlClient; global using RentADeveloper.DbConnectionPlus.Configuration; -global using RentADeveloper.DbConnectionPlus.DatabaseAdapters; global using RentADeveloper.DbConnectionPlus.Entities; diff --git a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerConfigurationExtensions.cs b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerConfigurationExtensions.cs index 58a3411..6d79479 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerConfigurationExtensions.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerConfigurationExtensions.cs @@ -1,6 +1,7 @@ using RentADeveloper.DbConnectionPlus.DatabaseAdapters.SqlServer; #pragma warning disable IDE0130 +// ReSharper disable once CheckNamespace namespace RentADeveloper.DbConnectionPlus.Configuration; #pragma warning restore IDE0130 diff --git a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerEntityManipulator.cs index 905eeaa..670f3ce 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerEntityManipulator.cs @@ -4,7 +4,6 @@ using LinkDotNet.StringBuilder; using RentADeveloper.DbConnectionPlus.Converters; using RentADeveloper.DbConnectionPlus.DbCommands; -using RentADeveloper.DbConnectionPlus.Entities; namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.SqlServer; diff --git a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerTemporaryTableBuilder.cs b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerTemporaryTableBuilder.cs index 119d1e4..5f6304a 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerTemporaryTableBuilder.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.SqlServer/SqlServerTemporaryTableBuilder.cs @@ -4,7 +4,6 @@ using LinkDotNet.StringBuilder; using Microsoft.Data; using RentADeveloper.DbConnectionPlus.DbCommands; -using RentADeveloper.DbConnectionPlus.Entities; using RentADeveloper.DbConnectionPlus.Extensions; using RentADeveloper.DbConnectionPlus.Readers; @@ -289,10 +288,10 @@ private static EnumerableReader CreateValuesDataReader( { if (valuesType.IsBuiltInTypeOrNullableBuiltInType() || valuesType.IsEnumOrNullableEnumType()) { - return new EnumerableReader(values, valuesType, Constants.SingleColumnTemporaryTableColumnName); + return new(values, valuesType, Constants.SingleColumnTemporaryTableColumnName); } - return new EnumerableReader( + return new( values, [.. EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a.CanRead)], EnumerableReaderOptions.None diff --git a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/GlobalUsings.cs b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/GlobalUsings.cs index cfc88dd..61f5ddc 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/GlobalUsings.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/GlobalUsings.cs @@ -4,5 +4,4 @@ global using System.Data.Common; global using System.Diagnostics.CodeAnalysis; global using RentADeveloper.DbConnectionPlus.Configuration; -global using RentADeveloper.DbConnectionPlus.DatabaseAdapters; global using RentADeveloper.DbConnectionPlus.Entities; diff --git a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteConfigurationExtensions.cs b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteConfigurationExtensions.cs index 50c090a..faaa029 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteConfigurationExtensions.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteConfigurationExtensions.cs @@ -2,6 +2,7 @@ using RentADeveloper.DbConnectionPlus.DatabaseAdapters.Sqlite; #pragma warning disable IDE0130 +// ReSharper disable once CheckNamespace namespace RentADeveloper.DbConnectionPlus.Configuration; #pragma warning restore IDE0130 diff --git a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteEntityManipulator.cs b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteEntityManipulator.cs index 371db8b..811c7b3 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteEntityManipulator.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteEntityManipulator.cs @@ -4,7 +4,6 @@ using LinkDotNet.StringBuilder; using RentADeveloper.DbConnectionPlus.Converters; using RentADeveloper.DbConnectionPlus.DbCommands; -using RentADeveloper.DbConnectionPlus.Entities; namespace RentADeveloper.DbConnectionPlus.DatabaseAdapters.Sqlite; diff --git a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteTemporaryTableBuilder.cs b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteTemporaryTableBuilder.cs index 4880fd6..ea9e86e 100644 --- a/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteTemporaryTableBuilder.cs +++ b/src/DbConnectionPlus.DatabaseAdapters.Sqlite/SqliteTemporaryTableBuilder.cs @@ -5,7 +5,6 @@ using Microsoft.Data.Sqlite; using RentADeveloper.DbConnectionPlus.Converters; using RentADeveloper.DbConnectionPlus.DbCommands; -using RentADeveloper.DbConnectionPlus.Entities; using RentADeveloper.DbConnectionPlus.Extensions; using RentADeveloper.DbConnectionPlus.Readers; @@ -291,10 +290,10 @@ private static EnumerableReader CreateValuesDataReader( { if (valuesType.IsBuiltInTypeOrNullableBuiltInType() || valuesType.IsEnumOrNullableEnumType()) { - return new EnumerableReader(values, valuesType, Constants.SingleColumnTemporaryTableColumnName); + return new(values, valuesType, Constants.SingleColumnTemporaryTableColumnName); } - return new EnumerableReader( + return new( values, [.. EntityHelper.GetEntityTypeMetadata(valuesType).MappedProperties.Where(a => a.CanRead)], EnumerableReaderOptions.None diff --git a/src/DbConnectionPlus/Configuration/DbConnectionPlusConfiguration.cs b/src/DbConnectionPlus/Configuration/DbConnectionPlusConfiguration.cs index dc170b8..418f914 100644 --- a/src/DbConnectionPlus/Configuration/DbConnectionPlusConfiguration.cs +++ b/src/DbConnectionPlus/Configuration/DbConnectionPlusConfiguration.cs @@ -84,6 +84,17 @@ public InterceptDbCommand? InterceptDbCommand } } + /// + void IFreezable.Freeze() + { + this.isFrozen = true; + + foreach (var entityTypeBuilder in this.entityTypeBuilders.Values) + { + entityTypeBuilder.Freeze(); + } + } + /// /// Gets a builder for configuring the entity type . /// @@ -174,15 +185,4 @@ private void EnsureNotFrozen() ThrowHelper.ThrowConfigurationIsFrozenException(); } } - - /// - void IFreezable.Freeze() - { - this.isFrozen = true; - - foreach (var entityTypeBuilder in this.entityTypeBuilders.Values) - { - entityTypeBuilder.Freeze(); - } - } } diff --git a/src/DbConnectionPlus/Configuration/EntityPropertyBuilder.cs b/src/DbConnectionPlus/Configuration/EntityPropertyBuilder.cs index 04a5c34..95d05b4 100644 --- a/src/DbConnectionPlus/Configuration/EntityPropertyBuilder.cs +++ b/src/DbConnectionPlus/Configuration/EntityPropertyBuilder.cs @@ -70,6 +70,9 @@ internal EntityPropertyBuilder(IEntityTypeBuilder entityTypeBuilder, string prop /// string IEntityPropertyBuilder.PropertyName => this.propertyName; + /// + void IFreezable.Freeze() => this.isFrozen = true; + /// /// Sets the name of the column to map the property to. /// @@ -213,7 +216,4 @@ private void EnsureNotFrozen() ThrowHelper.ThrowConfigurationIsFrozenException(); } } - - /// - void IFreezable.Freeze() => this.isFrozen = true; } diff --git a/src/DbConnectionPlus/Configuration/EntityTypeBuilder.cs b/src/DbConnectionPlus/Configuration/EntityTypeBuilder.cs index 13bb76f..dd45f46 100644 --- a/src/DbConnectionPlus/Configuration/EntityTypeBuilder.cs +++ b/src/DbConnectionPlus/Configuration/EntityTypeBuilder.cs @@ -22,6 +22,17 @@ public sealed class EntityTypeBuilder : IEntityTypeBuilder /// string? IEntityTypeBuilder.TableName => this.tableName; + /// + void IFreezable.Freeze() + { + this.isFrozen = true; + + foreach (var propertyBuilder in this.propertyBuilders.Values) + { + propertyBuilder.Freeze(); + } + } + /// /// Gets a builder for configuring the specified property. /// @@ -101,15 +112,4 @@ private void EnsureNotFrozen() ThrowHelper.ThrowConfigurationIsFrozenException(); } } - - /// - void IFreezable.Freeze() - { - this.isFrozen = true; - - foreach (var propertyBuilder in this.propertyBuilders.Values) - { - propertyBuilder.Freeze(); - } - } } diff --git a/src/DbConnectionPlus/Converters/EnumConverter.cs b/src/DbConnectionPlus/Converters/EnumConverter.cs index 45bce3e..2c30baa 100644 --- a/src/DbConnectionPlus/Converters/EnumConverter.cs +++ b/src/DbConnectionPlus/Converters/EnumConverter.cs @@ -1,7 +1,6 @@ // Copyright (c) 2026 David Liebeherr // Licensed under the MIT License. See LICENSE.md in the project root for more information. -using System.Diagnostics.CodeAnalysis; using RentADeveloper.DbConnectionPlus.Extensions; namespace RentADeveloper.DbConnectionPlus.Converters; diff --git a/src/DbConnectionPlus/Converters/ValueConverter.cs b/src/DbConnectionPlus/Converters/ValueConverter.cs index 03389d1..f65c99c 100644 --- a/src/DbConnectionPlus/Converters/ValueConverter.cs +++ b/src/DbConnectionPlus/Converters/ValueConverter.cs @@ -1,7 +1,6 @@ // Copyright (c) 2026 David Liebeherr // Licensed under the MIT License. See LICENSE.md in the project root for more information. -using System.Diagnostics.CodeAnalysis; using RentADeveloper.DbConnectionPlus.Extensions; namespace RentADeveloper.DbConnectionPlus.Converters; @@ -129,7 +128,7 @@ internal static class ValueConverter (typeof(long), typeof(ushort)), (typeof(long), typeof(uint)), (typeof(long), typeof(ulong)), - (typeof(IntPtr), typeof(IntPtr)), + (typeof(nint), typeof(nint)), (typeof(sbyte), typeof(bool)), (typeof(sbyte), typeof(byte)), (typeof(sbyte), typeof(char)), @@ -224,7 +223,7 @@ internal static class ValueConverter (typeof(ulong), typeof(ushort)), (typeof(ulong), typeof(uint)), (typeof(ulong), typeof(ulong)), - (typeof(UIntPtr), typeof(UIntPtr)), + (typeof(nuint), typeof(nuint)), ]; /// diff --git a/src/DbConnectionPlus/DbConnectionExtensions.Configuration.cs b/src/DbConnectionPlus/DbConnectionExtensions.Configuration.cs index 50093a8..cbe1a42 100644 --- a/src/DbConnectionPlus/DbConnectionExtensions.Configuration.cs +++ b/src/DbConnectionPlus/DbConnectionExtensions.Configuration.cs @@ -1,7 +1,6 @@ // Copyright (c) 2026 David Liebeherr // Licensed under the MIT License. See LICENSE.md in the project root for more information. -using RentADeveloper.DbConnectionPlus.Entities; using RentADeveloper.DbConnectionPlus.SqlStatements; namespace RentADeveloper.DbConnectionPlus; diff --git a/src/DbConnectionPlus/Dynamic/DataRow.cs b/src/DbConnectionPlus/Dynamic/DataRow.cs index 8bada07..d127e83 100644 --- a/src/DbConnectionPlus/Dynamic/DataRow.cs +++ b/src/DbConnectionPlus/Dynamic/DataRow.cs @@ -58,6 +58,9 @@ public class DataRow(IDictionary columns) : IDictionary writeColumn = static (row, columnName, value) => row[columnName] = value; + /// + /// The columns of the data row, keyed by column name. + /// private readonly IDictionary columns = columns; /// @@ -79,6 +82,12 @@ public object? this[string key] set => this.columns[key] = value; } + /// + IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); + + /// + DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) => this.GetMetaObject(parameter); + /// public void Add(KeyValuePair item) => this.columns.Add(item); @@ -121,12 +130,6 @@ public object? this[string key] /// protected virtual DynamicMetaObject GetMetaObject(Expression parameter) => new DataRowMetaObject(parameter, this); - /// - IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); - - /// - DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) => this.GetMetaObject(parameter); - /// /// Binds member access on a to the columns of the row, so that row.Id resolves to /// the same column as row["Id"]. diff --git a/src/DbConnectionPlus/Extensions/ObjectExtensions.cs b/src/DbConnectionPlus/Extensions/ObjectExtensions.cs index 0d3c6c4..2dc2a3d 100644 --- a/src/DbConnectionPlus/Extensions/ObjectExtensions.cs +++ b/src/DbConnectionPlus/Extensions/ObjectExtensions.cs @@ -84,7 +84,7 @@ private static string FormatValue(object? value, int depth) => long int64Value => int64Value.ToString("G", CultureInfo.InvariantCulture), - IntPtr intPtrValue => intPtrValue.ToString("G", CultureInfo.InvariantCulture), + nint intPtrValue => intPtrValue.ToString("G", CultureInfo.InvariantCulture), sbyte sbyteValue => sbyteValue.ToString("G", CultureInfo.InvariantCulture), @@ -100,7 +100,7 @@ private static string FormatValue(object? value, int depth) => ulong uint64Value => uint64Value.ToString("G", CultureInfo.InvariantCulture), - UIntPtr uintPtrValue => uintPtrValue.ToString("G", CultureInfo.InvariantCulture), + nuint uintPtrValue => uintPtrValue.ToString("G", CultureInfo.InvariantCulture), // Must stay below the Byte[] and String arms above, both of which are sequences that have // a more useful representation of their own. diff --git a/src/DbConnectionPlus/Extensions/TypeExtensions.cs b/src/DbConnectionPlus/Extensions/TypeExtensions.cs index 098391f..5273972 100644 --- a/src/DbConnectionPlus/Extensions/TypeExtensions.cs +++ b/src/DbConnectionPlus/Extensions/TypeExtensions.cs @@ -23,8 +23,8 @@ internal static class TypeExtensions typeof(uint), typeof(long), typeof(ulong), - typeof(IntPtr), - typeof(UIntPtr), + typeof(nint), + typeof(nuint), typeof(string), typeof(DateTime), typeof(DateOnly), diff --git a/src/DbConnectionPlus/Materializers/EntityMaterializerFactory.cs b/src/DbConnectionPlus/Materializers/EntityMaterializerFactory.cs index b664e42..12a2f9f 100644 --- a/src/DbConnectionPlus/Materializers/EntityMaterializerFactory.cs +++ b/src/DbConnectionPlus/Materializers/EntityMaterializerFactory.cs @@ -4,7 +4,6 @@ using System.Linq.Expressions; using System.Reflection; using RentADeveloper.DbConnectionPlus.Converters; -using RentADeveloper.DbConnectionPlus.Entities; using RentADeveloper.DbConnectionPlus.Extensions; namespace RentADeveloper.DbConnectionPlus.Materializers; @@ -619,18 +618,17 @@ ConstructorInfo compatibleConstructor && ValueConverter.CanConvert(dataReaderFieldType, p.ParameterType) ); - constructorArgumentBindings[Array.IndexOf(constructorParameters, constructorParameter)] = - new ReflectionColumnBinding( - dataReaderFieldName, + constructorArgumentBindings[Array.IndexOf(constructorParameters, constructorParameter)] = new( + dataReaderFieldName, + fieldOrdinal, + MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueFunction( fieldOrdinal, - MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueFunction( - fieldOrdinal, - dataReaderFieldName, - dataReaderFieldType - ), - dataReaderFieldType != constructorParameter.ParameterType, - constructorParameter.ParameterType - ); + dataReaderFieldName, + dataReaderFieldType + ), + dataReaderFieldType != constructorParameter.ParameterType, + constructorParameter.ParameterType + ); } var entityConstructor = ConstructorInvoker.Create(compatibleConstructor); @@ -1071,15 +1069,15 @@ Type[] dataReaderFieldTypes private string[] DataReaderFieldNames { get; } = dataReaderFieldNames; private Type[] DataReaderFieldTypes { get; } = dataReaderFieldTypes; - /// - public override bool Equals(object? obj) => obj is MaterializerCacheKey other && this.Equals(other); - /// public bool Equals(MaterializerCacheKey other) => this.EntityType == other.EntityType && this.DataReaderFieldNames.SequenceEqual(other.DataReaderFieldNames) && this.DataReaderFieldTypes.SequenceEqual(other.DataReaderFieldTypes); + /// + public override bool Equals(object? obj) => obj is MaterializerCacheKey other && this.Equals(other); + /// public override int GetHashCode() { diff --git a/src/DbConnectionPlus/Materializers/MaterializerFactoryHelper.cs b/src/DbConnectionPlus/Materializers/MaterializerFactoryHelper.cs index 8514087..827eec9 100644 --- a/src/DbConnectionPlus/Materializers/MaterializerFactoryHelper.cs +++ b/src/DbConnectionPlus/Materializers/MaterializerFactoryHelper.cs @@ -97,13 +97,13 @@ internal static class MaterializerFactoryHelper /// The method. /// internal static MethodInfo StringConcatMethod { get; } = - typeof(string).GetMethod(nameof(String.Concat), [typeof(string), typeof(string), typeof(string)])!; + typeof(string).GetMethod(nameof(string.Concat), [typeof(string), typeof(string), typeof(string)])!; /// /// The property. /// internal static PropertyInfo StringLengthProperty { get; } = - typeof(string).GetProperty(nameof(String.Length), BindingFlags.Instance | BindingFlags.Public)!; + typeof(string).GetProperty(nameof(string.Length), BindingFlags.Instance | BindingFlags.Public)!; /// /// Creates an that gets the value of a field of the specified field type from a diff --git a/src/DbConnectionPlus/Materializers/ValueTupleMaterializerFactory.cs b/src/DbConnectionPlus/Materializers/ValueTupleMaterializerFactory.cs index da16181..c2e827f 100644 --- a/src/DbConnectionPlus/Materializers/ValueTupleMaterializerFactory.cs +++ b/src/DbConnectionPlus/Materializers/ValueTupleMaterializerFactory.cs @@ -142,7 +142,7 @@ internal static Func CreateReflectionMaterializer< var dataReaderFieldType = dataReaderFieldTypes[fieldOrdinal]; var targetType = valueTupleFieldTypes[fieldOrdinal]; - columnBindings[fieldOrdinal] = new ReflectionColumnBinding( + columnBindings[fieldOrdinal] = new( GetColumnNameOrPosition(fieldOrdinal, dataReaderFieldName), fieldOrdinal, MaterializerFactoryHelper.CreateGetDbDataReaderFieldValueFunction( @@ -969,15 +969,15 @@ Type[] dataReaderFieldTypes private Type[] DataReaderFieldTypes { get; } = dataReaderFieldTypes; private Type[] ValueTupleFieldTypes { get; } = valueTupleFieldTypes; - /// - public override bool Equals(object? obj) => obj is MaterializerCacheKey other && this.Equals(other); - /// public bool Equals(MaterializerCacheKey other) => this.ValueTupleFieldTypes.SequenceEqual(other.ValueTupleFieldTypes) && this.DataReaderFieldNames.SequenceEqual(other.DataReaderFieldNames) && this.DataReaderFieldTypes.SequenceEqual(other.DataReaderFieldTypes); + /// + public override bool Equals(object? obj) => obj is MaterializerCacheKey other && this.Equals(other); + /// public override int GetHashCode() { diff --git a/src/DbConnectionPlus/Readers/EnumerableReader.cs b/src/DbConnectionPlus/Readers/EnumerableReader.cs index 9714033..6b1a427 100644 --- a/src/DbConnectionPlus/Readers/EnumerableReader.cs +++ b/src/DbConnectionPlus/Readers/EnumerableReader.cs @@ -96,10 +96,10 @@ string fieldName /// /// The sequence of entities from which the reader will read values. /// - /// The metadata of the properties that become the columns of the reader, in column order. Every entry must be + /// The metadata of the properties that become the columns of the reader in column order. Every entry must be /// readable, that is, expose a . /// - /// The behaviours the reader applies to the values it reads. + /// The behaviors the reader applies to the values it reads. /// /// /// @@ -299,8 +299,8 @@ public override string GetName(int ordinal) /// /// - /// The reader reads a single column and the specified field name is not the field name - /// that was passed to the constructor of this class. + /// The reader reads a single column, and the specified field name is not the field name + /// passed to the constructor of this class. /// /// /// In multi-column mode an unknown name yields -1 rather than an exception, which is what the @@ -363,7 +363,7 @@ public override object GetValue(int ordinal) /// The reader reads a single column and does not have a length of at least 1. /// /// - /// In multi-column mode a buffer shorter than is filled as far as it reaches and the + /// In multi-column mode a buffer shorter than is filled as far as it reaches, and the /// number of values written is returned, as specifies. /// public override int GetValues(object[] values) @@ -528,14 +528,14 @@ private static Type MapBuiltInFieldType(Type propertyType) return typeof(ulong); } - if (propertyType == typeof(IntPtr)) + if (propertyType == typeof(nint)) { - return typeof(IntPtr); + return typeof(nint); } - if (propertyType == typeof(UIntPtr)) + if (propertyType == typeof(nuint)) { - return typeof(UIntPtr); + return typeof(nuint); } if (propertyType == typeof(string)) @@ -580,7 +580,7 @@ private static Type MapBuiltInFieldType(Type propertyType) /// Resolves the type a column is reported as from the type of the property it is mapped to. /// /// The type of the property the column is mapped to. - /// The behaviours the reader applies to the values it reads. + /// The behaviors the reader applies to the values it reads. /// The type the column is reported as. /// /// The configured is not a defined value. diff --git a/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatement.cs b/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatement.cs index 08196f8..e925c27 100644 --- a/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatement.cs +++ b/src/DbConnectionPlus/SqlStatements/InterpolatedSqlStatement.cs @@ -163,10 +163,10 @@ public static InterpolatedSqlStatement FromString(string value) } /// - public override readonly bool Equals(object? obj) => obj is InterpolatedSqlStatement other && this.Equals(other); + public readonly bool Equals(InterpolatedSqlStatement other) => this.fragments.SequenceEqual(other.Fragments); /// - public readonly bool Equals(InterpolatedSqlStatement other) => this.fragments.SequenceEqual(other.Fragments); + public override readonly bool Equals(object? obj) => obj is InterpolatedSqlStatement other && this.Equals(other); /// public override readonly int GetHashCode() diff --git a/src/DbConnectionPlus/ThrowHelper.cs b/src/DbConnectionPlus/ThrowHelper.cs index 48d3aee..12c9416 100644 --- a/src/DbConnectionPlus/ThrowHelper.cs +++ b/src/DbConnectionPlus/ThrowHelper.cs @@ -1,7 +1,6 @@ // Copyright (c) 2026 David Liebeherr // Licensed under the MIT License. See LICENSE.md in the project root for more information. -using System.Diagnostics.CodeAnalysis; using RentADeveloper.DbConnectionPlus.Exceptions; using RentADeveloper.DbConnectionPlus.Extensions; diff --git a/tests/DbConnectionPlus.IntegrationTests/GlobalUsings.cs b/tests/DbConnectionPlus.IntegrationTests/GlobalUsings.cs index 68c98e3..81ac856 100644 --- a/tests/DbConnectionPlus.IntegrationTests/GlobalUsings.cs +++ b/tests/DbConnectionPlus.IntegrationTests/GlobalUsings.cs @@ -8,5 +8,4 @@ global using RentADeveloper.DbConnectionPlus.IntegrationTests.TestDatabase; global using RentADeveloper.DbConnectionPlus.SqlStatements; global using RentADeveloper.DbConnectionPlus.UnitTests.TestData; -global using Xunit; global using DataRow = RentADeveloper.DbConnectionPlus.Dynamic.DataRow; diff --git a/tests/DbConnectionPlus.UnitTests/Converters/ValueConverterTests.cs b/tests/DbConnectionPlus.UnitTests/Converters/ValueConverterTests.cs index 65c587a..80a95db 100644 --- a/tests/DbConnectionPlus.UnitTests/Converters/ValueConverterTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Converters/ValueConverterTests.cs @@ -24,7 +24,7 @@ object ExpectedTargetValue { var faker = new Faker(); - // All numeric values are kept within the range 0-127 so they are convertible to the smallest target type + // All numeric values are kept within the range 0-127, so they are convertible to the smallest target type // (SByte) without overflow. var byteValue = faker.Random.Byte(0, 127); var charValue = faker.Random.Char('A', 'Z'); @@ -37,7 +37,7 @@ object ExpectedTargetValue var int16Value = faker.Random.Short(0, 127); var int32Value = faker.Random.Int(0, 127); var int64Value = faker.Random.Long(0, 127); - var intPtrValue = (IntPtr)faker.Random.Int(0, 127); + var intPtrValue = (nint)faker.Random.Int(0, 127); var sbyteValue = faker.Random.SByte(0); var singleValue = faker.Random.Float(0, 127); var stringValue = faker.Lorem.Sentence(); @@ -46,7 +46,7 @@ object ExpectedTargetValue var uint64Value = faker.Random.ULong(0, 127); var timeSpanValue = faker.Date.Timespan(TimeSpan.FromHours(23)); var timeOnlyValue = faker.Date.RecentTimeOnly(); - var uintPtrValue = (UIntPtr)faker.Random.Int(0, 127); + var uintPtrValue = (nuint)faker.Random.Int(0, 127); var enumValue = faker.Random.Enum(); // @formatter:off @@ -325,8 +325,8 @@ object ExpectedTargetValue (typeof(long), typeof(ushort), true, int64Value, (ushort)int64Value), (typeof(long), typeof(uint), true, int64Value, (uint)int64Value), (typeof(long), typeof(ulong), true, int64Value, (ulong)int64Value), - (typeof(IntPtr), typeof(IntPtr), true, intPtrValue, intPtrValue), - (typeof(IntPtr), typeof(object), true, intPtrValue, intPtrValue), + (typeof(nint), typeof(nint), true, intPtrValue, intPtrValue), + (typeof(nint), typeof(object), true, intPtrValue, intPtrValue), (typeof(sbyte), typeof(bool), true, (sbyte)1, true), (typeof(sbyte), typeof(byte), true, sbyteValue, (byte)sbyteValue), (typeof(sbyte), typeof(char), true, sbyteValue, (char)sbyteValue), @@ -550,8 +550,8 @@ object ExpectedTargetValue (typeof(ulong), typeof(ushort), true, uint64Value, (ushort)uint64Value), (typeof(ulong), typeof(uint), true, uint64Value, (uint)uint64Value), (typeof(ulong), typeof(ulong), true, uint64Value, uint64Value), - (typeof(UIntPtr), typeof(object), true, uintPtrValue, uintPtrValue), - (typeof(UIntPtr), typeof(UIntPtr), true, uintPtrValue, uintPtrValue), + (typeof(nuint), typeof(object), true, uintPtrValue, uintPtrValue), + (typeof(nuint), typeof(nuint), true, uintPtrValue, uintPtrValue), (typeof(char), typeof(Guid), false, charValue, null), (typeof(int), typeof(Guid), false, int32Value, null), (typeof(DateTime), typeof(Guid), false, dateTimeValue, null), @@ -1181,7 +1181,7 @@ public void ShouldGuardAgainstNullArguments() /// /// Runs with the current culture set to , - /// and restores the previous culture afterwards. + /// and restores the previous culture afterward. /// /// /// pins every test to en-US, and en-US is exactly the culture under which diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryOfTTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryOfTTests.cs index 98d3d8d..2564366 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryOfTTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryOfTTests.cs @@ -13,6 +13,11 @@ public DbConnectionExtensions_QueryOfTTests() .QueryAsync(sql, transaction, timeout, commandType, cancellationToken) .ToListAsync(TestContext.Current.CancellationToken) .AsTask(), + // Keep this a method call. The lambda is an Action, so its body has to be a STATEMENT, and + // `[.. connection.Query(...)]` is a collection expression - not a valid statement, so it does + // not compile (CS0201). Editors and agents offer that rewrite as a one-click fix; it breaks + // the build. No analyzer suppression is needed - neither `dotnet format style` nor ReSharper's + // cleanup asks for it here, both verified. (connection, sql, transaction, timeout, commandType, cancellationToken) => connection.Query(sql, transaction, timeout, commandType, cancellationToken).ToList() ) diff --git a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryTests.cs b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryTests.cs index 97b6bd5..786eff5 100644 --- a/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryTests.cs +++ b/tests/DbConnectionPlus.UnitTests/DbConnectionExtensions.QueryTests.cs @@ -13,6 +13,11 @@ public DbConnectionExtensions_QueryTests() .QueryAsync(sql, transaction, timeout, commandType, cancellationToken) .ToListAsync(cancellationToken) .AsTask(), + // Keep this a method call. The lambda is an Action, so its body has to be a STATEMENT, and + // `[.. connection.Query(...)]` is a collection expression - not a valid statement, so it does + // not compile (CS0201). Editors and agents offer that rewrite as a one-click fix; it breaks + // the build. No analyzer suppression is needed - neither `dotnet format style` nor ReSharper's + // cleanup asks for it here, both verified. (connection, sql, transaction, timeout, commandType, cancellationToken) => connection.Query(sql, transaction, timeout, commandType, cancellationToken).ToList() ) diff --git a/tests/DbConnectionPlus.UnitTests/Extensions/ObjectExtensionsTests.cs b/tests/DbConnectionPlus.UnitTests/Extensions/ObjectExtensionsTests.cs index e651843..f1b1e14 100644 --- a/tests/DbConnectionPlus.UnitTests/Extensions/ObjectExtensionsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Extensions/ObjectExtensionsTests.cs @@ -80,7 +80,7 @@ public void ToDebugString_ShouldReturnStringRepresentationOfValue() ((long)123).ToDebugString().Should().Be("'123' (System.Int64)"); - ((IntPtr)123).ToDebugString().Should().Be("'123' (System.IntPtr)"); + ((nint)123).ToDebugString().Should().Be("'123' (System.IntPtr)"); ((sbyte)123).ToDebugString().Should().Be("'123' (System.SByte)"); @@ -96,7 +96,7 @@ public void ToDebugString_ShouldReturnStringRepresentationOfValue() ((ulong)123).ToDebugString().Should().Be("'123' (System.UInt64)"); - ((UIntPtr)123).ToDebugString().Should().Be("'123' (System.UIntPtr)"); + ((nuint)123).ToDebugString().Should().Be("'123' (System.UIntPtr)"); #pragma warning disable CA1861 // Avoid constant arrays as arguments new int[] { 1, 2, 3 } @@ -124,7 +124,7 @@ public void ToDebugString_ShouldTruncateSelfReferencingSequencesInsteadOfRecursi values.Add(values); // The depth bound replaces the cycle handling that the previous JsonSerializer-based implementation got - // from ReferenceHandler.IgnoreCycles. What matters is that this terminates at all; the exact nesting + // from ReferenceHandler.IgnoreCycles. What matters is that this terminates completely; the exact nesting // depth at which it stops is an implementation detail. var debugString = values.ToDebugString(); diff --git a/tests/DbConnectionPlus.UnitTests/Extensions/TypeExtensionsTests.cs b/tests/DbConnectionPlus.UnitTests/Extensions/TypeExtensionsTests.cs index 6bc158d..a493591 100644 --- a/tests/DbConnectionPlus.UnitTests/Extensions/TypeExtensionsTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Extensions/TypeExtensionsTests.cs @@ -32,8 +32,8 @@ public class TypeExtensionsTests : UnitTestsBase [InlineData(typeof(int?), true)] [InlineData(typeof(long), true)] [InlineData(typeof(long?), true)] - [InlineData(typeof(IntPtr), true)] - [InlineData(typeof(IntPtr?), true)] + [InlineData(typeof(nint), true)] + [InlineData(typeof(nint?), true)] [InlineData(typeof(sbyte), true)] [InlineData(typeof(sbyte?), true)] [InlineData(typeof(float), true)] @@ -49,8 +49,8 @@ public class TypeExtensionsTests : UnitTestsBase [InlineData(typeof(uint?), true)] [InlineData(typeof(ulong), true)] [InlineData(typeof(ulong?), true)] - [InlineData(typeof(UIntPtr), true)] - [InlineData(typeof(UIntPtr?), true)] + [InlineData(typeof(nuint), true)] + [InlineData(typeof(nuint?), true)] [InlineData(typeof(Entity), false)] [InlineData(typeof(TestEnum), false)] public void IsBuiltInTypeOrNullableBuiltInType_ShouldDetermineWhetherTypeIsBuiltInTypeOrNullableBuiltInType( diff --git a/tests/DbConnectionPlus.UnitTests/GlobalUsings.cs b/tests/DbConnectionPlus.UnitTests/GlobalUsings.cs index e9bd802..5e88c20 100644 --- a/tests/DbConnectionPlus.UnitTests/GlobalUsings.cs +++ b/tests/DbConnectionPlus.UnitTests/GlobalUsings.cs @@ -11,4 +11,3 @@ global using RentADeveloper.DbConnectionPlus.Configuration; global using static RentADeveloper.DbConnectionPlus.DbConnectionExtensions; global using RentADeveloper.DbConnectionPlus.UnitTests.TestData; -global using Xunit; diff --git a/tests/DbConnectionPlus.UnitTests/Materializers/MaterializerFactoryHelperTests.cs b/tests/DbConnectionPlus.UnitTests/Materializers/MaterializerFactoryHelperTests.cs index fc15492..999772b 100644 --- a/tests/DbConnectionPlus.UnitTests/Materializers/MaterializerFactoryHelperTests.cs +++ b/tests/DbConnectionPlus.UnitTests/Materializers/MaterializerFactoryHelperTests.cs @@ -335,7 +335,7 @@ public void StringConcatMethod_ShouldReferenceStringConcatWithThreeStringParamet method.DeclaringType.Should().Be(typeof(string)); - method.Name.Should().Be(nameof(String.Concat)); + method.Name.Should().Be(nameof(string.Concat)); method .GetParameters() @@ -353,7 +353,7 @@ public void StringLengthProperty_ShouldReferenceStringLengthProperty() property.DeclaringType.Should().Be(typeof(string)); - property.Name.Should().Be(nameof(String.Length)); + property.Name.Should().Be(nameof(string.Length)); property.PropertyType.Should().Be(typeof(int)); } diff --git a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithPublicConstructor.cs b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithPublicConstructor.cs index bcc330e..7aa90ab 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/EntityWithPublicConstructor.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/EntityWithPublicConstructor.cs @@ -1,5 +1,7 @@ // ReSharper disable ConvertToPrimaryConstructor +// An explicit public constructor is the whole point of this fixture: it is what the constructor-injection +// materializer binds to. A primary constructor would change what is under test. #pragma warning disable IDE0290 namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; diff --git a/tests/DbConnectionPlus.UnitTests/TestData/Generate.cs b/tests/DbConnectionPlus.UnitTests/TestData/Generate.cs index 83ff74c..141dd4f 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/Generate.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/Generate.cs @@ -38,10 +38,10 @@ static Generate() fixture.Customize(new OmitIgnoredPropertiesCustomization()); - fixture.Register(() => faker.Random.Bool()); - fixture.Register(() => faker.Random.Byte()); - fixture.Register(() => faker.Random.Bytes(SmallNumber())); - fixture.Register(() => characters[faker.Random.Int(0, characters.Length - 1)]); + fixture.Register(() => faker.Random.Bool()); + fixture.Register(() => faker.Random.Byte()); + fixture.Register(() => faker.Random.Bytes(SmallNumber())); + fixture.Register(() => characters[faker.Random.Int(0, characters.Length - 1)]); fixture.Register(() => faker.Date.PastDateOnly()); fixture.Register(() => { @@ -73,26 +73,26 @@ static Generate() dateTimeOffset.Offset ); }); - fixture.Register(() => + fixture.Register(() => { // We limit to 10 fractional digits because not all database systems support a higher precision. return Math.Round(faker.Random.Decimal(0, 999), 10); }); - fixture.Register(() => + fixture.Register(() => { // We limit to 3 fractional digits because not all database systems support a higher precision. return Math.Round(faker.Random.Double(0, 999), 3); }); fixture.Register(() => faker.Random.Guid()); - fixture.Register(() => faker.Random.Short()); - fixture.Register(() => faker.Random.Int()); - fixture.Register(() => Interlocked.Increment(ref entityId)); - fixture.Register(() => + fixture.Register(() => faker.Random.Short()); + fixture.Register(() => faker.Random.Int()); + fixture.Register(() => Interlocked.Increment(ref entityId)); + fixture.Register(() => { // We limit to 3 fractional digits because not all database systems support a higher precision. return (float)Math.Round(faker.Random.Float(0, 999), 3); }); - fixture.Register(() => faker.Lorem.Sentence()); + fixture.Register(() => faker.Lorem.Sentence()); fixture.Register(() => faker.Random.Enum()); fixture.Register(() => { diff --git a/tests/DbConnectionPlus.UnitTests/TestData/ItemWithConstructor.cs b/tests/DbConnectionPlus.UnitTests/TestData/ItemWithConstructor.cs index 5d7a968..482d343 100644 --- a/tests/DbConnectionPlus.UnitTests/TestData/ItemWithConstructor.cs +++ b/tests/DbConnectionPlus.UnitTests/TestData/ItemWithConstructor.cs @@ -1,5 +1,7 @@ // ReSharper disable ConvertToPrimaryConstructor +// An explicit public constructor is the whole point of this fixture: it is what the constructor-injection +// materializer binds to. A primary constructor would change what is under test. #pragma warning disable IDE0290 namespace RentADeveloper.DbConnectionPlus.UnitTests.TestData; diff --git a/tests/package-consumption/AllAdaptersConsumer/Program.cs b/tests/package-consumption/AllAdaptersConsumer/Program.cs index e17b079..1ad668b 100644 --- a/tests/package-consumption/AllAdaptersConsumer/Program.cs +++ b/tests/package-consumption/AllAdaptersConsumer/Program.cs @@ -40,9 +40,9 @@ public static class Program { /// The entry point. /// Zero if every assertion passed, otherwise one. - public static Int32 Main() + public static int Main() { - Console.WriteLine(new String('=', 100)); + Console.WriteLine(new string('=', 100)); Console.WriteLine("DbConnectionPlus - all-adapters package consumer"); Console.WriteLine(); Console.WriteLine($" runtime {Environment.Version}"); @@ -67,7 +67,7 @@ public static Int32 Main() } Console.WriteLine(); - Console.WriteLine(new String('=', 100)); + Console.WriteLine(new string('=', 100)); if (Check.FailureCount == 0) { @@ -138,7 +138,7 @@ private static void AssertDriverPackagesFlowedTransitively() /// The name of the adapter the driver belongs to. /// The freshly constructed, unopened connection. /// The simple name of the assembly the type must come from. - private static void AssertConnectionType(String adapter, DbConnection connection, String expectedAssemblyName) + private static void AssertConnectionType(string adapter, DbConnection connection, string expectedAssemblyName) { using (connection) { @@ -232,8 +232,8 @@ public sealed class Widget { /// The primary key. Not database-generated, so it takes part in the INSERT. [Key] - public Int64 Id { get; set; } + public long Id { get; set; } /// A plain string column. - public String Name { get; set; } = String.Empty; + public string Name { get; set; } = string.Empty; } diff --git a/tests/package-consumption/AotConsumer/Model.cs b/tests/package-consumption/AotConsumer/Model.cs index 52ace2c..48f7e7a 100644 --- a/tests/package-consumption/AotConsumer/Model.cs +++ b/tests/package-consumption/AotConsumer/Model.cs @@ -49,16 +49,16 @@ public sealed class SmokeEntity { /// The primary key. Not database-generated, so it takes part in the INSERT. [Key] - public Int64 Id { get; set; } + public long Id { get; set; } /// A plain string column. - public String Name { get; set; } = String.Empty; + public string Name { get; set; } = string.Empty; /// Stored as TEXT by SQLite, so materializing it exercises a String to Decimal conversion. - public Decimal Balance { get; set; } + public decimal Balance { get; set; } /// Stored as INTEGER by SQLite, so materializing it exercises an Int64 to Boolean conversion. - public Boolean IsActive { get; set; } + public bool IsActive { get; set; } /// Stored as TEXT by SQLite, so materializing it exercises a String to DateTime conversion. public DateTime CreatedAt { get; set; } @@ -70,7 +70,7 @@ public sealed class SmokeEntity public SmokeStatus Status { get; set; } /// SQLite reports INTEGER columns as , so this narrows on materialization. - public Int32 Quantity { get; set; } + public int Quantity { get; set; } } /// @@ -83,7 +83,7 @@ public sealed class ImmutableSmokeEntity /// The primary key. /// The name. /// The balance. - public ImmutableSmokeEntity(Int64 id, String name, Decimal balance) + public ImmutableSmokeEntity(long id, string name, decimal balance) { this.Id = id; this.Name = name; @@ -91,13 +91,13 @@ public ImmutableSmokeEntity(Int64 id, String name, Decimal balance) } /// The primary key. - public Int64 Id { get; } + public long Id { get; } /// The name. - public String Name { get; } + public string Name { get; } /// The balance. - public Decimal Balance { get; } + public decimal Balance { get; } } // ===================================================================================================== @@ -194,8 +194,8 @@ public sealed class SmokeItem { /// The primary key. [Key] - public Int64 Id { get; set; } + public long Id { get; set; } /// The label of the item. - public String Label { get; set; } = String.Empty; + public string Label { get; set; } = string.Empty; } diff --git a/tests/package-consumption/AotConsumer/Program.cs b/tests/package-consumption/AotConsumer/Program.cs index 5c06da5..ef18888 100644 --- a/tests/package-consumption/AotConsumer/Program.cs +++ b/tests/package-consumption/AotConsumer/Program.cs @@ -30,11 +30,11 @@ public static class Program { /// The entry point. /// Zero if every assertion passed, otherwise one. - public static Int32 Main() + public static int Main() { var databasePath = Path.Combine(Path.GetTempPath(), $"dbconnectionplus-aot-consumer-{Guid.NewGuid():N}.db"); - Console.WriteLine(new String('=', 100)); + Console.WriteLine(new string('=', 100)); Console.WriteLine("DbConnectionPlus - Native AOT package consumer"); Console.WriteLine(); var packageAssembly = typeof(DbConnectionPlusConfiguration).Assembly.GetName(); @@ -90,7 +90,7 @@ public static Int32 Main() } Console.WriteLine(); - Console.WriteLine(new String('=', 100)); + Console.WriteLine(new string('=', 100)); if (Check.FailureCount == 0) { diff --git a/tests/package-consumption/AotConsumer/SmokeCases.cs b/tests/package-consumption/AotConsumer/SmokeCases.cs index 4422820..42b6421 100644 --- a/tests/package-consumption/AotConsumer/SmokeCases.cs +++ b/tests/package-consumption/AotConsumer/SmokeCases.cs @@ -29,7 +29,7 @@ public static class SmokeCases }; /// The primary key of the single row the enum cases read. - private const Int64 EnumRowId = 1; + private const long EnumRowId = 1; /// /// Creates the tables the remaining cases read from, and writes the row the enum cases read. @@ -95,7 +95,7 @@ public static void InsertEntity(DbConnection connection) Check.Equal( "the row is readable again", 1L, - connection.ExecuteScalar("SELECT COUNT(*) FROM SmokeEntity") + connection.ExecuteScalar("SELECT COUNT(*) FROM SmokeEntity") ); } @@ -184,10 +184,10 @@ public static void QueryImmutableEntity(DbConnection connection) /// The open connection to the temporary SQLite database. public static void QueryValueTuple(DbConnection connection) { - Check.Section("5. Query<(Int64, String, Decimal)> - value tuple"); + Check.Section("5. Query<(long, string, decimal)> - value tuple"); var (id, name, balance) = connection - .Query<(Int64 Id, String Name, Decimal Balance)>( + .Query<(long Id, string Name, decimal Balance)>( $"SELECT Id, Name, Balance FROM SmokeEntity WHERE Id = {ExpectedEntity.Id}" ) .Single(); @@ -213,7 +213,7 @@ public static void QueryNestedValueTuple(DbConnection connection) Check.Section("6. Query<(...8 fields)> - nested value tuple (TRest)"); var tuple = connection - .Query<(Int64 A, Int64 B, Int64 C, Int64 D, Int64 E, Int64 F, Int64 G, String H)>( + .Query<(long A, long B, long C, long D, long E, long F, long G, string H)>( $""" SELECT Id AS A, Quantity AS B, Id AS C, Quantity AS D, Id AS E, Quantity AS F, Id AS G, Name AS H FROM SmokeEntity @@ -223,7 +223,7 @@ FROM SmokeEntity .Single(); Check.Equal("field 1", ExpectedEntity.Id, tuple.A); - Check.Equal("field 2", (Int64)ExpectedEntity.Quantity, tuple.B); + Check.Equal("field 2", (long)ExpectedEntity.Quantity, tuple.B); Check.Equal("field 7", ExpectedEntity.Id, tuple.G); Check.Equal("field 8 (nested in TRest)", ExpectedEntity.Name, tuple.H); } @@ -244,7 +244,7 @@ public static void QueryDataRow(DbConnection connection) var row = connection.Query($"SELECT Id, Name FROM SmokeEntity WHERE Id = {ExpectedEntity.Id}").Single(); Check.Equal("row[\"Id\"]", ExpectedEntity.Id, Convert.ToInt64(row["Id"], null)); - Check.Equal("row[\"Name\"]", ExpectedEntity.Name, row["Name"] as String); + Check.Equal("row[\"Name\"]", ExpectedEntity.Name, row["Name"] as string); } /// Streams a single-column temporary table into the database and reads it back. @@ -253,9 +253,9 @@ public static void SingleColumnTemporaryTable(DbConnection connection) { Check.Section("8. TemporaryTable - single column"); - var values = new List { 10, 20, 30 }; + var values = new List { 10, 20, 30 }; - var read = connection.Query($"SELECT Value FROM {TemporaryTable(values)} ORDER BY Value").ToList(); + var read = connection.Query($"SELECT Value FROM {TemporaryTable(values)} ORDER BY Value").ToList(); Check.Equal("three values round-trip", 3, read.Count); Check.True("the values are unchanged", read.SequenceEqual(values)); @@ -332,16 +332,16 @@ public static void ZeroBindingGuard(DbConnection connection) /// public static void QueryValueTupleWithANumericEnum(DbConnection connection) { - Check.Section("11. Query<(Int64, enum)> - enum field of a flat value tuple, from an INTEGER column"); + Check.Section("11. Query<(long, enum)> - enum field of a flat value tuple, from an INTEGER column"); var (id, status) = connection - .Query<(Int64 Id, FlatTupleNumericEnum Status)>( + .Query<(long Id, FlatTupleNumericEnum Status)>( $"SELECT Id, FlatNumeric AS Status FROM SmokeEnum WHERE Id = {EnumRowId}" ) .Single(); Check.Equal("Id", EnumRowId, id); - Check.Equal("the enum field binds the stored value", 71, (Int32)status); + Check.Equal("the enum field binds the stored value", 71, (int)status); } /// @@ -361,7 +361,7 @@ public static void QueryNestedValueTupleWithANumericEnum(DbConnection connection Check.Section("12. Query<(...8 fields)> - enum field nested in TRest, from an INTEGER column"); var tuple = connection - .Query<(Int64 A, Int64 B, Int64 C, Int64 D, Int64 E, Int64 F, Int64 G, NestedTupleNumericEnum H)>( + .Query<(long A, long B, long C, long D, long E, long F, long G, NestedTupleNumericEnum H)>( $""" SELECT Id AS A, Id AS B, Id AS C, Id AS D, Id AS E, Id AS F, Id AS G, NestedNumeric AS H FROM SmokeEnum @@ -371,7 +371,7 @@ FROM SmokeEnum .Single(); Check.Equal("field 1", EnumRowId, tuple.A); - Check.Equal("field 8 (enum nested in TRest) binds the stored value", 81, (Int32)tuple.H); + Check.Equal("field 8 (enum nested in TRest) binds the stored value", 81, (int)tuple.H); } /// @@ -388,16 +388,16 @@ FROM SmokeEnum /// public static void QueryValueTupleWithANamedEnum(DbConnection connection) { - Check.Section("13. Query<(Int64, enum)> - enum field of a flat value tuple, parsed from a TEXT column"); + Check.Section("13. Query<(long, enum)> - enum field of a flat value tuple, parsed from a TEXT column"); var (id, status) = connection - .Query<(Int64 Id, FlatTupleNamedEnum Status)>( + .Query<(long Id, FlatTupleNamedEnum Status)>( $"SELECT Id, FlatNamed AS Status FROM SmokeEnum WHERE Id = {EnumRowId}" ) .Single(); Check.Equal("Id", EnumRowId, id); - Check.Equal("the name in the column parsed to the right member", 91, (Int32)status); + Check.Equal("the name in the column parsed to the right member", 91, (int)status); Check.Equal("the member name survived trimming", "FlatNamedChosen", status.ToString()); } @@ -419,7 +419,7 @@ public static void QueryNestedValueTupleWithANamedEnum(DbConnection connection) Check.Section("14. Query<(...8 fields)> - enum field nested in TRest, parsed from a TEXT column"); var tuple = connection - .Query<(Int64 A, Int64 B, Int64 C, Int64 D, Int64 E, Int64 F, Int64 G, NestedTupleNamedEnum H)>( + .Query<(long A, long B, long C, long D, long E, long F, long G, NestedTupleNamedEnum H)>( $""" SELECT Id AS A, Id AS B, Id AS C, Id AS D, Id AS E, Id AS F, Id AS G, NestedNamed AS H FROM SmokeEnum @@ -429,7 +429,7 @@ FROM SmokeEnum .Single(); Check.Equal("field 1", EnumRowId, tuple.A); - Check.Equal("field 8 (enum nested in TRest) parsed to the right member", 101, (Int32)tuple.H); + Check.Equal("field 8 (enum nested in TRest) parsed to the right member", 101, (int)tuple.H); Check.Equal("the member name survived trimming", "NestedNamedChosen", tuple.H.ToString()); } } diff --git a/tests/package-consumption/Check.cs b/tests/package-consumption/Check.cs index 6ba94fc..11ad626 100644 --- a/tests/package-consumption/Check.cs +++ b/tests/package-consumption/Check.cs @@ -24,14 +24,14 @@ namespace RentADeveloper.DbConnectionPlus.PackageConsumption; public static class Check { /// Gets the number of assertions that failed so far. - public static Int32 FailureCount { get; private set; } + public static int FailureCount { get; private set; } /// Writes a section header, so the console output stays readable in a CI log. /// The title of the section. - public static void Section(String title) + public static void Section(string title) { Console.WriteLine(); - Console.WriteLine(new String('=', 100)); + Console.WriteLine(new string('=', 100)); Console.WriteLine(title); Console.WriteLine(); } @@ -41,7 +41,7 @@ public static void Section(String title) /// A description of what is being asserted. /// The expected value. /// The actual value. - public static void Equal(String label, T expected, T actual) + public static void Equal(string label, T expected, T actual) { if (EqualityComparer.Default.Equals(expected, actual)) { @@ -56,7 +56,7 @@ public static void Equal(String label, T expected, T actual) /// Asserts that is . /// A description of what is being asserted. /// The condition that must hold. - public static void True(String label, Boolean condition) + public static void True(string label, bool condition) { if (condition) { @@ -76,7 +76,7 @@ public static void True(String label, Boolean condition) /// A description of what is being asserted. /// A fragment the exception message must contain. /// The action that must throw. - public static void Throws(String label, String expectedMessageFragment, Action action) + public static void Throws(string label, string expectedMessageFragment, Action action) where TException : Exception { try @@ -108,9 +108,9 @@ public static void Throws(String label, String expectedMessageFragme Fail(label, $"expected {typeof(TException).Name}, but nothing was thrown"); } - private static void Pass(String label) => Console.WriteLine($" PASS {label}"); + private static void Pass(string label) => Console.WriteLine($" PASS {label}"); - private static void Fail(String label, String detail) + private static void Fail(string label, string detail) { FailureCount++; @@ -118,12 +118,12 @@ private static void Fail(String label, String detail) Console.WriteLine($" {detail}"); } - private static String Render(Object? value) => + private static string Render(object? value) => value switch { null => "null", - Byte[] bytes => Convert.ToHexString(bytes), + byte[] bytes => Convert.ToHexString(bytes), IFormattable formattable => formattable.ToString(null, CultureInfo.InvariantCulture), - _ => value.ToString() ?? String.Empty, + _ => value.ToString() ?? string.Empty, }; } From 5f826832d1336deb5fb1cb4a8aa9d54409c95679 Mon Sep 17 00:00:00 2001 From: David Liebeherr Date: Thu, 27 Aug 2026 06:58:38 +0200 Subject: [PATCH 10/12] build: one entry point for style, formatting and ordering scripts/format-cs.ps1 becomes scripts/tidy-cs.ps1, in three scopes: (default) ~1s CSharpier, on the files git reports as changed -Scope style ~15s + the Roslyn code-style fixers -Scope all ~3min + member reordering, whole solution -Check reports instead of fixing. With -Scope all it still WRITES, and that is not a shortcut: cleanupcode re-indents raw string literals and CSharpier puts them back, so neither is idempotent alone and asking either in isolation always answers yes. The pair is, so it tidies for real and compares the tree before against after. Both editor hooks run the default scope; preflight.ps1 runs -Scope all before the build; CI's lint job runs -Check -Scope all, so CI cannot disagree with the local tooling. CI also fails if a .git-blame-ignore-revs entry stops resolving - git does not warn about one it cannot resolve, it silently skips it. Every dotnet call goes through one helper that relaxes $ErrorActionPreference: at Stop, PowerShell turns anything a native tool writes to stderr into a terminating error, and ReSharper writes a harmless warning most runs. Part of #21 Co-Authored-By: Claude Opus 5 --- .claude/hooks/format-cs.ps1 | 31 -- .claude/hooks/tidy-cs.ps1 | 42 +++ .claude/settings.json | 2 +- .codex/hooks.json | 2 +- .codex/hooks/{format-cs.ps1 => tidy-cs.ps1} | 20 +- .github/workflows/ci.yml | 83 +++++- scripts/format-cs.ps1 | 123 -------- scripts/preflight.ps1 | 57 +++- scripts/tidy-cs.ps1 | 312 ++++++++++++++++++++ 9 files changed, 496 insertions(+), 176 deletions(-) delete mode 100644 .claude/hooks/format-cs.ps1 create mode 100644 .claude/hooks/tidy-cs.ps1 rename .codex/hooks/{format-cs.ps1 => tidy-cs.ps1} (69%) delete mode 100644 scripts/format-cs.ps1 create mode 100644 scripts/tidy-cs.ps1 diff --git a/.claude/hooks/format-cs.ps1 b/.claude/hooks/format-cs.ps1 deleted file mode 100644 index d0f78c8..0000000 --- a/.claude/hooks/format-cs.ps1 +++ /dev/null @@ -1,31 +0,0 @@ -# PostToolUse hook: format an edited C# file against .editorconfig. -# -# The formatting logic itself lives in scripts/format-cs.ps1, so that Codex's hook and a human run -# exactly the same thing. This file is only the hook wiring: read the tool payload off stdin, pull the -# edited path out of it, and delegate. -# -# Never fails the edit - a formatter problem is surfaced as text and the hook still exits 0. - -$ErrorActionPreference = 'Stop' - -try { - $payload = [Console]::In.ReadToEnd() | ConvertFrom-Json - $filePath = $payload.tool_input.file_path - - if ([String]::IsNullOrWhiteSpace($filePath)) { exit 0 } - if ([System.IO.Path]::GetExtension($filePath) -ne '.cs') { exit 0 } - if (-not (Test-Path -LiteralPath $filePath)) { exit 0 } - - $script = Join-Path (Split-Path -Parent (Split-Path -Parent $PSScriptRoot)) 'scripts/format-cs.ps1' - if (-not (Test-Path -LiteralPath $script)) { - Write-Output "format-cs hook: scripts/format-cs.ps1 not found at $script" - exit 0 - } - - & $script -Path $filePath -} -catch { - Write-Output "format-cs hook error: $($_.Exception.Message)" -} - -exit 0 diff --git a/.claude/hooks/tidy-cs.ps1 b/.claude/hooks/tidy-cs.ps1 new file mode 100644 index 0000000..b1f45ed --- /dev/null +++ b/.claude/hooks/tidy-cs.ps1 @@ -0,0 +1,42 @@ +# PostToolUse hook: format an edited C# file with CSharpier. +# +# The logic itself lives in scripts/tidy-cs.ps1, so that Codex's hook and a human run exactly the same +# thing. This file is only the hook wiring: read the tool payload off stdin, pull the edited path out of +# it, and delegate. +# +# Formatting only, which is the default scope and takes under a second. Style and member ordering are +# not run here: `dotnet format style` needs MSBuild and ReSharper loads the whole solution, and neither +# belongs on the critical path of every single edit. All three are build errors, and scripts/preflight.ps1 +# runs `-Scope all` before a commit, so nothing slips through. +# +# Never fails the edit - a formatter problem is surfaced as text and the hook still exits 0. + +$ErrorActionPreference = 'Stop' + +try { + $payload = [Console]::In.ReadToEnd() | ConvertFrom-Json + $filePath = $payload.tool_input.file_path + + if ([String]::IsNullOrWhiteSpace($filePath)) { exit 0 } + if ([System.IO.Path]::GetExtension($filePath) -ne '.cs') { exit 0 } + if (-not (Test-Path -LiteralPath $filePath)) { exit 0 } + + $script = Join-Path (Split-Path -Parent (Split-Path -Parent $PSScriptRoot)) 'scripts/tidy-cs.ps1' + if (-not (Test-Path -LiteralPath $script)) { + Write-Output "tidy-cs hook: scripts/tidy-cs.ps1 not found at $script" + exit 0 + } + + $output = & $script -Path $filePath 2>&1 | Out-String + + # Quiet on success. On failure say so explicitly and say what it means, because the build treats + # formatting as an error - the same contract Codex's adapter reports through additionalContext. + if ($LASTEXITCODE -ne 0) { + Write-Output "CSharpier failed on $filePath. The build treats formatting as an error, so fix this before building:`n$output" + } +} +catch { + Write-Output "tidy-cs hook error: $($_.Exception.Message)" +} + +exit 0 diff --git a/.claude/settings.json b/.claude/settings.json index 4b9217f..49ce5d4 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -7,7 +7,7 @@ "hooks": [ { "type": "command", - "command": "pwsh -NoProfile -NonInteractive -File \"$CLAUDE_PROJECT_DIR/.claude/hooks/format-cs.ps1\"", + "command": "pwsh -NoProfile -NonInteractive -File \"$CLAUDE_PROJECT_DIR/.claude/hooks/tidy-cs.ps1\"", "timeout": 60 }, { diff --git a/.codex/hooks.json b/.codex/hooks.json index cb4110c..3d7122c 100644 --- a/.codex/hooks.json +++ b/.codex/hooks.json @@ -7,7 +7,7 @@ "hooks": [ { "type": "command", - "command": "pwsh -NoProfile -NonInteractive -Command \"& (Join-Path (git rev-parse --show-toplevel) '.codex/hooks/format-cs.ps1')\"", + "command": "pwsh -NoProfile -NonInteractive -Command \"& (Join-Path (git rev-parse --show-toplevel) '.codex/hooks/tidy-cs.ps1')\"", "statusMessage": "Formatting changed C# files", "timeout": 120 }, diff --git a/.codex/hooks/format-cs.ps1 b/.codex/hooks/tidy-cs.ps1 similarity index 69% rename from .codex/hooks/format-cs.ps1 rename to .codex/hooks/tidy-cs.ps1 index d5524e1..17570e0 100644 --- a/.codex/hooks/format-cs.ps1 +++ b/.codex/hooks/tidy-cs.ps1 @@ -1,13 +1,17 @@ -# Codex PostToolUse hook: format the C# files an edit just touched, against .editorconfig. +# Codex PostToolUse hook: format the C# files an edit just touched, with CSharpier. # -# The formatting logic itself lives in scripts/format-cs.ps1, which Claude Code's hook runs too. -# This file is only the hook wiring. +# The logic itself lives in scripts/tidy-cs.ps1, which Claude Code's hook runs too. This file is only +# the hook wiring. # # Why it does not read a path out of the payload: for a file edit Codex reports tool_name "apply_patch" and # puts the patch text in tool_input.command, not a file path. The script with no arguments formats # every .cs file git reports as changed, which covers the edit that just happened and costs nothing when # there is none. # +# Formatting only, which is the default scope. Style and member ordering are build errors and +# scripts/preflight.ps1 runs `-Scope all` before a commit; neither belongs on the critical path of +# every edit. +# # Contract (https://learn.chatgpt.com/docs/hooks): exit 0 and write the response JSON to stdout. Exit code 2 # would block the operation - this hook never does that, because a formatter problem must not stop an edit. @@ -41,25 +45,25 @@ try { $repositoryRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) } - $script = Join-Path $repositoryRoot 'scripts/format-cs.ps1' + $script = Join-Path $repositoryRoot 'scripts/tidy-cs.ps1' if (-not (Test-Path -LiteralPath $script)) { - Write-HookResult -AdditionalContext "format-cs hook: scripts/format-cs.ps1 not found at $script" + Write-HookResult -AdditionalContext "tidy-cs hook: scripts/tidy-cs.ps1 not found at $script" exit 0 } $output = & pwsh -NoProfile -NonInteractive -File $script 2>&1 | Out-String # Quiet on success: the agent does not need to be told that nothing needed formatting. A failure is - # reported, because it means the next build breaks on a style rule. + # reported, because it means the next build breaks on a formatting rule. if ($LASTEXITCODE -ne 0) { - Write-HookResult -AdditionalContext "dotnet format failed. The build treats style rules as errors, so fix this before building:`n$output" + Write-HookResult -AdditionalContext "CSharpier failed. The build treats formatting as an error, so fix this before building:`n$output" } else { Write-HookResult } } catch { - Write-HookResult -AdditionalContext "format-cs hook error: $($_.Exception.Message)" + Write-HookResult -AdditionalContext "tidy-cs hook error: $($_.Exception.Message)" } exit 0 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3a91b01..da04ec6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,23 +37,80 @@ env: TESTINGPLATFORM_TELEMETRY_OPTOUT: true jobs: - # Enforce the formatting the repo ships tooling for. A style rule that is not enforced in CI drifts with - # the first external pull request. + # Enforce the style, formatting and member ordering the repo ships tooling for. A rule that is not + # enforced in CI drifts with the first external pull request. # - # Whitespace only: the semantic style and analyzer rules are already enforced by the build itself - # (EnforceCodeStyleInBuild + TreatWarningsAsErrors + Roslynator at error) in the verify job below. What - # that does NOT cover is tests/ and benchmarks/, which set neither property - so for those projects this - # job is the only formatting gate there is. + # This runs scripts/tidy-cs.ps1, the same entry point a developer and both AI agents use, so CI cannot + # disagree with what the tooling produces locally. -Check -Scope all tidies the checkout for real and + # then asks whether anything changed: ReSharper has no check mode, and neither it nor CSharpier is + # idempotent alone, so comparing before against after is the only honest question. Writing to the + # checkout is harmless here - it is thrown away at the end of the job. + # + # All three are also build errors in the verify job below, for every project - style and ordering through + # the analyzers, formatting through CSharpier.MsBuild. This job still earns its place: it is much faster to + # a red X, and it prints the exact diff that would fix things rather than only naming the file. It is also + # the only check that can see a MISPLACED member the analyzers accept, because alphabetical order within a + # group is a ReSharper notion that StyleCop does not model. + # + # It also guards .git-blame-ignore-revs, which is repository hygiene of the same kind: a rule nothing + # checks stops being true. See the step for why that file cannot report its own breakage. lint: name: Lint runs-on: ubuntu-latest - timeout-minutes: 15 + timeout-minutes: 25 steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: persist-credentials: false + # Full history, for the .git-blame-ignore-revs check below. At the default depth of 1 none of the + # revisions it names would resolve and every run would fail. Nothing else in this job needs it. + fetch-depth: 0 + + # .git-blame-ignore-revs names commits by raw SHA, and git does NOT complain about one it cannot + # resolve - it silently skips the entry. The file then still looks right while doing nothing, and blame + # goes back to pointing at the tool that reformatted a line instead of at whoever wrote it. + # + # A rebase-merge or a squash-merge rewrites every SHA on a branch, which is exactly how that happens, + # and it happens quietly, months after the click. This step is the only thing that makes it visible. + # + # It runs before the .NET setup on purpose: it needs nothing but the checkout, so a broken file fails in + # seconds instead of after the three-minute tidy run below. + - name: Verify .git-blame-ignore-revs + run: | + if [ ! -f .git-blame-ignore-revs ]; then + echo "No .git-blame-ignore-revs - nothing to check." + exit 0 + fi + + status=0 + count=0 + while read -r revision _ || [ -n "${revision}" ]; do + revision="${revision%$'\r'}" + case "${revision}" in ''|\#*) continue ;; esac + count=$((count + 1)) + + if ! git rev-parse --verify --quiet "${revision}^{commit}" > /dev/null; then + echo "::error file=.git-blame-ignore-revs::${revision} is not a commit in this repository. If the branch that introduced it was rebased or squash-merged, replace it with the SHA it became." + status=1 + elif ! git merge-base --is-ancestor "${revision}" HEAD; then + echo "::error file=.git-blame-ignore-revs::${revision} is a commit, but not an ancestor of HEAD, so blame can never reach it." + status=1 + fi + done < .git-blame-ignore-revs + + if [ "${count}" -eq 0 ]; then + echo "::error file=.git-blame-ignore-revs::The file lists no revisions. Delete it if it is no longer wanted, rather than leaving an empty one that looks like it is doing something." + exit 1 + fi + + if [ "${status}" -ne 0 ]; then + echo "Checked ${count} revision(s); see the errors above." + exit 1 + fi + + echo "All ${count} revision(s) resolve and are reachable." - name: Setup .NET uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 @@ -74,8 +131,16 @@ jobs: - name: Restore run: dotnet restore ${{ env.SOLUTION }} --configfile ${{ env.NUGET_CONFIG }} - - name: Verify C# formatting (dotnet format) - run: dotnet format whitespace ${{ env.SOLUTION }} --no-restore --verify-no-changes + - name: Restore .NET tools + run: dotnet tool restore + + - name: Verify style, formatting and member ordering + run: pwsh -NoProfile -NonInteractive -File scripts/tidy-cs.ps1 -Scope all -Check + + # The check above only says that something is untidy. This says what. + - name: Show the changes that would fix it + if: failure() + run: git --no-pager diff --stat && git --no-pager diff # Build the solution, run both test suites against real databases, and hand the coverage to Codecov. # diff --git a/scripts/format-cs.ps1 b/scripts/format-cs.ps1 deleted file mode 100644 index 5765545..0000000 --- a/scripts/format-cs.ps1 +++ /dev/null @@ -1,123 +0,0 @@ -<# -.SYNOPSIS - Formats C# files against .editorconfig, the way this repository's build expects them. - -.DESCRIPTION - This repo builds with TreatWarningsAsErrors=true, AnalysisLevel=latest-all, EnforceCodeStyleInBuild=true, - and .editorconfig puts csharp_style_expression_bodied_* at `error` severity. A style slip is therefore a - hard build break, and fixing it at edit time is much cheaper than discovering it at build time. - - AI agents call this from a PostToolUse hook after every .cs edit - Claude Code through - .claude/hooks/format-cs.ps1 and Codex through .codex/hooks/format-cs.ps1. A human runs it before - building. Keep the logic here rather than in a hook, so all three run the same thing. - -.PARAMETER Path - One or more .cs files to format. With no Path, every .cs file git reports as changed (tracked - modifications plus untracked files) is formatted. - -.PARAMETER Scope - How much dotnet format does: - style ~4s - IDExxxx code-style rules, incl. the expression-bodied ones. Default. - all ~9s - whitespace + style + 3rd-party analyzers (Roslynator, ErrorProne.NET). - whitespace ~2s - indentation and spacing only. - -.EXAMPLE - pwsh -File scripts/format-cs.ps1 - -.EXAMPLE - pwsh -File scripts/format-cs.ps1 src/DbConnectionPlus/Entities/EntityHelper.cs -#> -[CmdletBinding()] -param( - [Parameter(Position = 0, ValueFromRemainingArguments = $true)] - [String[]] $Path, - - [ValidateSet('style', 'all', 'whitespace')] - [String] $Scope = 'style' -) - -$ErrorActionPreference = 'Stop' - -# scripts/ - the repository root is one level up. -$repositoryRoot = Split-Path -Parent $PSScriptRoot - -function Get-ChangedCSharpFile { - param([String] $RepositoryRoot) - - # 2>$null: git warns about CRLF normalization per file, which is noise here. - $tracked = & git -C $RepositoryRoot diff --name-only HEAD -- '*.cs' 2>$null - $untracked = & git -C $RepositoryRoot ls-files --others --exclude-standard -- '*.cs' 2>$null - - return @($tracked) + @($untracked) | - Where-Object { $_ } | - ForEach-Object { Join-Path $RepositoryRoot $_ } -} - -function Get-OwningProject { - param([String] $FilePath) - - $directory = Split-Path -Parent $FilePath - while ($directory) { - $candidate = Get-ChildItem -LiteralPath $directory -Filter '*.csproj' -File -ErrorAction SilentlyContinue | - Select-Object -First 1 - if ($candidate) { return $candidate.FullName } - $directory = Split-Path -Parent $directory - } - - return $null -} - -if (-not $Path -or $Path.Count -eq 0) { - $Path = Get-ChangedCSharpFile -RepositoryRoot $repositoryRoot -} - -$files = @($Path) | - Where-Object { $_ } | - Where-Object { [System.IO.Path]::GetExtension($_) -eq '.cs' } | - Where-Object { Test-Path -LiteralPath $_ -PathType Leaf } | - ForEach-Object { (Resolve-Path -LiteralPath $_).Path } | - # Generated and build output are not ours to format. - Where-Object { $_ -notmatch '[\\/](bin|obj)[\\/]' } | - Select-Object -Unique - -if ($files.Count -eq 0) { - Write-Output 'format-cs: nothing to format.' - exit 0 -} - -$failed = $false - -# One dotnet format invocation per owning project, so MSBuild loads one project rather than the solution. -$files | Group-Object { Get-OwningProject -FilePath $_ } | ForEach-Object { - $project = $_.Name - if ([String]::IsNullOrWhiteSpace($project) -or -not (Test-Path -LiteralPath $project)) { - Write-Output "format-cs: no owning .csproj for $($_.Group -join ', ') - skipped." - return - } - - $projectDirectory = Split-Path -Parent $project - - # `--include` matches RELATIVE paths only. Handed an absolute path it matches nothing, reports success - # and formats nothing - a silent no-op that looks exactly like a clean file. So run from the project - # directory and pass each file relative to it. - $relativePaths = $_.Group | ForEach-Object { [System.IO.Path]::GetRelativePath($projectDirectory, $_) } - - $arguments = @('format') - if ($Scope -ne 'all') { $arguments += $Scope } - $arguments += @($project, '--include') + $relativePaths + @('--no-restore', '-v', 'q') - - Push-Location -LiteralPath $projectDirectory - try { $output = & dotnet @arguments 2>&1 } - finally { Pop-Location } - - if ($LASTEXITCODE -ne 0) { - $failed = $true - Write-Output "format-cs: dotnet format failed for $(Split-Path -Leaf $project):`n$output" - } - else { - Write-Output "format-cs: formatted $($relativePaths.Count) file(s) in $(Split-Path -Leaf $project)." - } -} - -if ($failed) { exit 1 } -exit 0 diff --git a/scripts/preflight.ps1 b/scripts/preflight.ps1 index b28e95e..dfcc322 100644 --- a/scripts/preflight.ps1 +++ b/scripts/preflight.ps1 @@ -1,6 +1,7 @@ <# .SYNOPSIS - The pre-commit gate: repo-hygiene checks, a Release build, and the unit test suite. + The pre-commit gate: repo-hygiene checks, style/formatting/ordering, a Release build, and the unit + test suite. .DESCRIPTION CONTRIBUTING.md requires that all tests pass and the build succeeds with no warnings. Because @@ -18,6 +19,9 @@ scripts/verify-package-aot.ps1 -Pack after any change to a reflection path; nothing else in the repository can see silent trimming damage. +.PARAMETER SkipTidy + Skip applying style, formatting and member ordering. The build still fails on any of them. + .PARAMETER SkipBuild Skip the Release build (implies -SkipTests). @@ -34,6 +38,7 @@ param( [Switch] $SkipBuild, [Switch] $SkipTests, + [Switch] $SkipTidy, [String] $Configuration = 'Release' ) @@ -43,6 +48,7 @@ $repositoryRoot = Split-Path -Parent $PSScriptRoot $solution = Join-Path $repositoryRoot 'DbConnectionPlus.slnx' $unitTests = Join-Path $repositoryRoot 'tests/DbConnectionPlus.UnitTests/DbConnectionPlus.UnitTests.csproj' $publicApiGuard = Join-Path $repositoryRoot 'scripts/public-api-guard.ps1' +$tidy = Join-Path $repositoryRoot 'scripts/tidy-cs.ps1' $failures = New-Object System.Collections.Generic.List[String] @@ -69,7 +75,52 @@ else { Write-Output 'Unchanged.' } -# --- 2. Build ---------------------------------------------------------------------------------------- +# --- 2. Style, formatting and member ordering --------------------------------------------------------- +# Applied, not just checked. All three are build errors, so leaving them to step 3 only means a slower +# way of finding out. The editor hooks format on every edit, but they deliberately skip the two slow +# tools - the code-style fixers and the member reordering - and this is where those run. +# +# It rewrites files. That is the point, and it is why this runs before the build. + +if (-not $SkipTidy) { + Write-Section 'Style, formatting and ordering' + + # Snapshot the dirty .cs files BEFORE tidying. `git diff` afterwards lists your own edits too, so + # reporting its count would say "tidied 40 files" when the tools touched one of them. What the run + # actually changed is the difference between the two lists. + $dirtyBefore = @(& git -C $repositoryRoot diff --name-only -- '*.cs' 2>$null | Where-Object { $_ }) + + & pwsh -NoProfile -NonInteractive -File $tidy -Scope all + if ($LASTEXITCODE -ne 0) { + $failures.Add('tidy') + Write-Output 'FAIL - tidy-cs could not finish. Run `dotnet tool restore` if the tools are missing.' + } + else { + $dirtyAfter = @(& git -C $repositoryRoot diff --name-only -- '*.cs' 2>$null | Where-Object { $_ }) + $tidied = @($dirtyAfter | Where-Object { $_ -notin $dirtyBefore }) + + Write-Output '' + if ($tidied) { + Write-Output "Tidied $($tidied.Count) file(s) that you had not already changed:" + $tidied | ForEach-Object { Write-Output " $_" } + Write-Output 'Review the diff and include it in your commit.' + } + elseif ($dirtyBefore) { + # Everything the tools touched was already in your diff, so there is nothing new to point at - + # but the tools may still have rewritten those files, and that is worth one line. + Write-Output "Tidy ran clean. Your $($dirtyBefore.Count) changed .cs file(s) may have been rewritten - review the diff." + } + else { + Write-Output 'Already tidy.' + } + } +} +else { + Write-Section 'Style, formatting and ordering' + Write-Output 'Skipped (-SkipTidy).' +} + +# --- 3. Build ---------------------------------------------------------------------------------------- if (-not $SkipBuild) { Write-Section "Build ($Configuration)" @@ -86,7 +137,7 @@ else { Write-Output 'Skipped (-SkipBuild).' } -# --- 3. Unit tests ----------------------------------------------------------------------------------- +# --- 4. Unit tests ----------------------------------------------------------------------------------- if (-not $SkipBuild -and -not $SkipTests -and -not $failures.Contains('build')) { Write-Section 'Unit tests' diff --git a/scripts/tidy-cs.ps1 b/scripts/tidy-cs.ps1 new file mode 100644 index 0000000..8043eb6 --- /dev/null +++ b/scripts/tidy-cs.ps1 @@ -0,0 +1,312 @@ +<# +.SYNOPSIS + Applies this repository's C# style, formatting and member ordering. + +.DESCRIPTION + Three concerns, three tools, no overlap between them: + + formatting whitespace, line breaks, wrapping CSharpier + style var, =>, this., null checks, usings Roslyn analyzers, via `dotnet format style` + ordering the order of types and their members ReSharper, via `jb cleanupcode` + + They run in that reverse order - style, then ordering, then formatting - because each one leaves + whitespace behind for the next. CSharpier is always last and always has the final say. + + The build enforces all three, in the tests and benchmarks as much as in the libraries: + EnforceCodeStyleInBuild with TreatWarningsAsErrors makes a style slip or a misplaced member an + error, and CSharpier.MsBuild does the same for an unformatted file. Running this first is much + cheaper than finding out at build time. + + Needs the local tools: run `dotnet tool restore` once per clone. + +.PARAMETER Path + One or more .cs files. With no Path, every .cs file git reports as changed - tracked modifications + plus untracked files. Ignored by -Scope all, which always covers the whole solution. + +.PARAMETER Scope + How much runs: + + format ~1s CSharpier only. The default, and what the editor hooks use. + style ~15s + the Roslyn code-style fixers. + all ~3min + member reordering. Whole solution only - ReSharper loads all of it either way. + This is the one to run before committing; scripts/preflight.ps1 does it for you. + +.PARAMETER Check + Report violations instead of fixing them, and exit non-zero if there are any. This is what CI runs. + + -Check -Scope all is the exception: it still WRITES. ReSharper has no check mode, and neither it nor + CSharpier is idempotent alone - cleanupcode re-indents the content of raw string literals and + CSharpier puts it back - so the only honest question is whether tidying the whole tree changes it. + That is what -Check -Scope all asks: it tidies for real, then compares. Do not point it at a working + tree you are not ready to have tidied. + +.EXAMPLE + pwsh -File scripts/tidy-cs.ps1 + +.EXAMPLE + pwsh -File scripts/tidy-cs.ps1 -Scope all + +.EXAMPLE + pwsh -File scripts/tidy-cs.ps1 src/DbConnectionPlus/Entities/EntityHelper.cs +#> +[CmdletBinding()] +param( + [Parameter(Position = 0, ValueFromRemainingArguments = $true)] + [String[]] $Path, + + [ValidateSet('format', 'style', 'all')] + [String] $Scope = 'format', + + [Switch] $Check +) + +$ErrorActionPreference = 'Stop' + +# scripts/ - the repository root is one level up. +$repositoryRoot = Split-Path -Parent $PSScriptRoot +$solution = Join-Path $repositoryRoot 'DbConnectionPlus.slnx' + +function Get-ChangedCSharpFile { + # 2>$null: git warns about CRLF normalization per file, which is noise here. + $tracked = & git -C $repositoryRoot diff --name-only HEAD -- '*.cs' 2>$null + $untracked = & git -C $repositoryRoot ls-files --others --exclude-standard -- '*.cs' 2>$null + + return @($tracked) + @($untracked) | + Where-Object { $_ } | + ForEach-Object { Join-Path $repositoryRoot $_ } +} + +function Get-OwningProject { + param([String] $FilePath) + + $directory = Split-Path -Parent $FilePath + while ($directory) { + $candidate = Get-ChildItem -LiteralPath $directory -Filter '*.csproj' -File -ErrorAction SilentlyContinue | + Select-Object -First 1 + if ($candidate) { return $candidate.FullName } + $directory = Split-Path -Parent $directory + } + + return $null +} + +function Resolve-TargetFile { + param([String[]] $Candidates) + + return @($Candidates) | + Where-Object { $_ } | + Where-Object { [System.IO.Path]::GetExtension($_) -eq '.cs' } | + Where-Object { Test-Path -LiteralPath $_ -PathType Leaf } | + ForEach-Object { (Resolve-Path -LiteralPath $_).Path } | + # Generated and build output are not ours to touch. + Where-Object { $_ -notmatch '[\\/](bin|obj)[\\/]' } | + Select-Object -Unique +} + +$failures = New-Object System.Collections.Generic.List[String] + +function Invoke-Tool { + <# + Runs `dotnet ...` and returns everything it printed. The caller decides success from $LASTEXITCODE. + + $ErrorActionPreference is deliberately relaxed for the call. With it at 'Stop', PowerShell turns + anything a native program writes to stderr into a terminating error, so a harmless warning aborts + the whole script with NativeCommandError. ReSharper prints one every run: + + Warning: Roslyn Source Generator error from DapperInterceptorGenerator from Dapper.AOT + handled 1 of 1 possible call-sites ... + + That is a notice, not a failure - cleanupcode still exits 0 - but it was enough to kill the script. + Exit codes decide success here, not stderr. + #> + param([Parameter(Mandatory)] [String[]] $Arguments) + + $previous = $ErrorActionPreference + $ErrorActionPreference = 'Continue' + try { return (& dotnet @Arguments 2>&1 | Out-String) } + finally { $ErrorActionPreference = $previous } +} + +# --- Style ---------------------------------------------------------------------------------------- +# The IDExxxx code-style rules, and the third-party analyzer fixers that have one. Whitespace rules are +# deliberately not included: IDE0055 is off in .editorconfig, because whitespace belongs to CSharpier. + +function Invoke-StyleFix { + param([String[]] $Files, [Boolean] $VerifyOnly) + + $verify = if ($VerifyOnly) { @('--verify-no-changes') } else { @() } + + if (-not $Files) { + $arguments = @('format', 'style', $solution, '--no-restore', '-v', 'q') + $verify + $output = Invoke-Tool -Arguments $arguments + if ($LASTEXITCODE -ne 0) { $failures.Add("dotnet format style:`n$output") } + return + } + + # tests/package-consumption/ is out of reach for this step, and the failure would be confusing rather + # than useful: those projects restore from the PACKED packages, so `dotnet format style` on one cannot + # even load it until `dotnet pack` has run. CSharpier still formats them - it needs no project - and the + # style rules there are on the author. See the code-style reference. + $consumers = [System.IO.Path]::Combine($repositoryRoot, 'tests', 'package-consumption') + $skipped = @($Files) | Where-Object { $_.StartsWith($consumers, [StringComparison]::OrdinalIgnoreCase) } + if ($skipped) { + Write-Output "tidy-cs: $($skipped.Count) file(s) under tests/package-consumption - no style pass, see AGENTS.md." + } + + $Files = @($Files) | Where-Object { -not $_.StartsWith($consumers, [StringComparison]::OrdinalIgnoreCase) } + if (-not $Files) { return } + + # One invocation per owning project, so MSBuild loads one project rather than the whole solution. + $Files | Group-Object { Get-OwningProject -FilePath $_ } | ForEach-Object { + $project = $_.Name + if ([String]::IsNullOrWhiteSpace($project) -or -not (Test-Path -LiteralPath $project)) { + Write-Output "tidy-cs: no owning .csproj for $($_.Group -join ', ') - skipped." + return + } + + $projectDirectory = Split-Path -Parent $project + + # `--include` matches RELATIVE paths only. Handed an absolute path it matches nothing, reports + # success and formats nothing - a silent no-op that looks exactly like a clean file. So run from + # the project directory and pass each file relative to it. + # + # The PROJECT has to be relative too, and that is the half that is easy to miss. Given an absolute + # project path, `dotnet format` reports "Formatted 0 of 0 files" and exits 0 whatever --include + # says, so this whole step was doing nothing at all until both halves were relative. Neither + # failure is visible without -v d. + $relativePaths = $_.Group | ForEach-Object { [System.IO.Path]::GetRelativePath($projectDirectory, $_) } + $projectFileName = Split-Path -Leaf $project + + $arguments = + @('format', 'style', $projectFileName, '--include') + + $relativePaths + + @('--no-restore', '-v', 'q') + + $verify + + Push-Location -LiteralPath $projectDirectory + try { $output = Invoke-Tool -Arguments $arguments } + finally { Pop-Location } + + if ($LASTEXITCODE -ne 0) { + $failures.Add("dotnet format style ($(Split-Path -Leaf $project)):`n$output") + } + } +} + +# --- Ordering ------------------------------------------------------------------------------------- +# ReSharper is the only tool that can reorder C# members. StyleCop reports a wrong order but cannot fix +# one: its ElementOrderCodeFixProvider is marked [NoCodeFix] and never registered. +# +# The order itself is the file layout in DbConnectionPlus.slnx.DotSettings, and the ReorderMembers +# profile in the same file enables member reordering and nothing else - no reformatting, because that +# is CSharpier's job. + +function Get-CSharpFingerprint { + # A hash over the content of every .cs file the tools actually touch, used by -Check to tell whether + # tidying changed anything. + # + # The file list comes from git, not from Get-ChildItem. Walking the directory tree finds 391 .cs + # files where the tools see 283: build leftovers and the package consumers' NuGet cache under + # tests/package-consumption/.packages/ are on disk but ignored, and CSharpier honours .gitignore. + # Hashing those makes the check fail on files nothing tidied. + # + # `git diff` is not used either: a human running -Check usually has a dirty tree, and their own + # edits are not an ordering violation. Comparing before against after answers the actual question. + $relativePaths = & git -C $repositoryRoot ls-files --cached --others --exclude-standard -- '*.cs' 2>$null | + Where-Object { $_ } | + Sort-Object + + # Fail loudly on an empty list rather than hashing nothing. git's stderr goes to $null just above, so a + # git that fails here returns no paths instead of an error - and two hashes of an empty stream compare + # equal, which would make -Check report a tidy tree without having looked at a single file. This is CI's + # only formatting gate; it must not be able to pass by accident. + if (-not $relativePaths) { + throw 'tidy-cs: git listed no .cs files. Is this a git repository, and is git on PATH?' + } + + $sha = [System.Security.Cryptography.SHA256]::Create() + try { + $accumulator = New-Object System.IO.MemoryStream + foreach ($relativePath in $relativePaths) { + $fullPath = Join-Path $repositoryRoot $relativePath + if (-not (Test-Path -LiteralPath $fullPath -PathType Leaf)) { continue } + + # The path goes into the hash too, so that adding or removing a file is a change. + $pathBytes = [System.Text.Encoding]::UTF8.GetBytes($relativePath) + $accumulator.Write($pathBytes, 0, $pathBytes.Length) + + $bytes = [System.IO.File]::ReadAllBytes($fullPath) + $accumulator.Write($bytes, 0, $bytes.Length) + } + + return [System.BitConverter]::ToString($sha.ComputeHash($accumulator.ToArray())) + } + finally { $sha.Dispose() } +} + +function Invoke-ReorderMembers { + $output = Invoke-Tool -Arguments @('jb', 'cleanupcode', $solution, '--profile=ReorderMembers', '--no-build') + if ($LASTEXITCODE -ne 0) { $failures.Add("jb cleanupcode:`n$output") } +} + +# --- Formatting ----------------------------------------------------------------------------------- +# Always last: both steps above move code around and leave whitespace that is not CSharpier's. + +function Invoke-Format { + param([String[]] $Files, [Boolean] $VerifyOnly) + + # @(...) around the whole thing on purpose: an `if` writes its result to the pipeline, which + # enumerates a one-element array back down to a bare string. Splatting that passes "C" as the path. + $target = @(if ($Files) { $Files } else { $repositoryRoot }) + $command = if ($VerifyOnly) { 'check' } else { 'format' } + + $output = Invoke-Tool -Arguments (@('csharpier', $command) + $target) + if ($LASTEXITCODE -ne 0) { $failures.Add("csharpier $command`:`n$output") } +} + +# --- Run ------------------------------------------------------------------------------------------ + +if ($Scope -eq 'all') { + if ($Path) { Write-Output 'tidy-cs: -Scope all covers the whole solution; the paths given are ignored.' } + + # -Check does not reach the individual tools here, because two of them are not idempotent on their + # own: cleanupcode re-indents the content of raw string literals and CSharpier puts it back. Asking + # cleanupcode alone whether it changed anything therefore always says yes. So the whole pipeline + # runs for real and the question is asked once, of the tree: did tidying it change anything? + $before = if ($Check) { Get-CSharpFingerprint } else { $null } + + Invoke-StyleFix -Files @() -VerifyOnly $false + Invoke-ReorderMembers + Invoke-Format -Files @() -VerifyOnly $false + + if ($Check -and -not $failures.Count -and (Get-CSharpFingerprint) -ne $before) { + $failures.Add('the tree is not tidy. Run: pwsh -File scripts/tidy-cs.ps1 -Scope all') + } + + if (-not $failures.Count) { + Write-Output "tidy-cs: solution $(if ($Check) { 'checked' } else { 'tidied' })." + } +} +else { + if (-not $Path) { $Path = Get-ChangedCSharpFile } + + $files = Resolve-TargetFile -Candidates $Path + if (-not $files) { + Write-Output 'tidy-cs: nothing to do.' + exit 0 + } + + if ($Scope -eq 'style') { Invoke-StyleFix -Files $files -VerifyOnly $Check.IsPresent } + Invoke-Format -Files $files -VerifyOnly $Check.IsPresent + + if (-not $failures.Count) { + Write-Output "tidy-cs: $($files.Count) file(s) $(if ($Check) { 'checked' } else { 'tidied' })." + } +} + +if ($failures.Count) { + $failures | ForEach-Object { Write-Output "tidy-cs: $_" } + exit 1 +} + +exit 0 From d04d473b5330a3d7313f4a2c12bfe936c7c7a51b Mon Sep 17 00:00:00 2001 From: David Liebeherr Date: Thu, 27 Aug 2026 06:58:39 +0200 Subject: [PATCH 11/12] docs: rewrite the code style guidance for agents and contributors AGENTS.md is the canonical guidance for both agent integrations and has a 200 line instruction budget, so the detail moves to .agents/references/code-style.md and AGENTS.md keeps the rules and the traps. What an author has to know, because no tool enforces it: - A primary constructor parameter goes into a private readonly backing field and is read through this.field. A captured parameter compiles to a field with no readonly, so using it directly drops that guarantee silently. - IDE0049 misses nint/nuint, nameof() and tests/package-consumption/. - Same-named overloads have no defined order; ReSharper's sort is stable and leaves them where it found them. Both orders are correct. - cleanupcode re-indents raw string literals and CSharpier puts them back. CONTRIBUTING.md gains a clone setup section, and Conventional Branch replaces the two-prefix branch rule that had no room for a change like this one. Part of #21 Co-Authored-By: Claude Opus 5 --- .agents/README.md | 8 +- .agents/references/code-style.md | 116 ++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 4 +- AGENTS.md | 384 +++++++++++-------------------- CLAUDE.md | 10 +- CONTRIBUTING.md | 40 +++- 6 files changed, 303 insertions(+), 259 deletions(-) create mode 100644 .agents/references/code-style.md diff --git a/.agents/README.md b/.agents/README.md index ce6cb95..eb52a69 100644 --- a/.agents/README.md +++ b/.agents/README.md @@ -5,6 +5,7 @@ Reusable AI-agent instructions have one canonical location: ```text AGENTS.md Repository guidance .agents/skills/*/SKILL.md Workflow procedures +.agents/references/*.md Reference material AGENTS.md links to .agents/references/reviews/*.md Review checklists scripts/*.ps1 Executable checks and workflows ``` @@ -26,7 +27,12 @@ Codex-only UI metadata and explicit-invocation policy. Claude needs thin skill w `disable-model-invocation` policy lives in `SKILL.md` frontmatter. The hook adapters differ because Claude and Codex use different payload and response contracts. Both delegate -all substantive behavior to the same scripts. +all substantive behavior to the same scripts: `scripts/tidy-cs.ps1` and `scripts/public-api-guard.ps1`. + +The tidy hook runs the **default scope only** — CSharpier, under a second. Code style and member ordering are +not run on every edit: `dotnet format style` needs MSBuild and ReSharper loads the whole solution, and neither +belongs on the critical path of a single edit. All three are build errors, and `scripts/preflight.ps1` runs +`tidy-cs.ps1 -Scope all` before a commit, so nothing reaches a pull request untidied. When changing behavior, edit the canonical file. Keep only required names, descriptions, policies, tool/model settings, and reference instructions in tool-specific files. diff --git a/.agents/references/code-style.md b/.agents/references/code-style.md new file mode 100644 index 0000000..083472b --- /dev/null +++ b/.agents/references/code-style.md @@ -0,0 +1,116 @@ +# Code style details + +Background for the rules in [AGENTS.md](../../AGENTS.md#code-style-formatting-and-ordering). Read this when a +tool does something you did not expect, or when you are about to write a type name in a place the build does +not check. + +## Three concerns, three tools + +| Concern | Tool | Configured in | +|---|---|---| +| Formatting — whitespace, line breaks, wrapping | **CSharpier** | `.editorconfig` (`max_line_length`, `indent_size`) | +| Style — `var`, `=>`, `this.`, null checks, usings | **Roslyn analyzers** | `.editorconfig` | +| Ordering — types and their members | **ReSharper** applies it, **NewStyleCop** checks it | `DbConnectionPlus.slnx.DotSettings` and `stylecop.json` | + +Each tool owns its concern completely, and all three are build errors rather than warnings, in `tests/` and +`benchmarks/` as much as in `src/`. Two different mechanisms, both in the root `Directory.Build.props`: +`EnforceCodeStyleInBuild=true` with `TreatWarningsAsErrors=true` covers style and ordering, and the +`CSharpier.MsBuild` package covers formatting. It runs in check mode, so a build never rewrites your files — +an unformatted file fails the build and names itself. `-p:CSharpier_Bypass=true` skips it. + +## Where the build misses a BCL type name + +The rule is: write `string`, `object?`, `int`, `bool`, `nint`, `nuint` — never `String`, `Object?`, `Int32`, +`Boolean`, `IntPtr`, `UIntPtr`. `dotnet_style_predefined_type_for_*` is `true:error`, and `IDE0049` enforces +most of it. + +`IDE0049` has two blind spots. Neither produces a diagnostic, so `TreatWarningsAsErrors` has nothing to fail +on. Both were verified against the analyzer: + +- **`nint`/`nuint` are not on its list.** They arrived in C# 9 as their own feature and only became aliases + for `IntPtr`/`UIntPtr` in C# 11; the analyzer was never extended. `IntPtr` is invisible to it. +- **It never looks inside `nameof(...)`.** With good reason: `nameof(int)` does not compile at all + (CS1525 — a keyword is not a name), so a blanket skip is the safe choice. Where `nameof` names a CLR type + on purpose, as in `EnumerableReaderTests`, leave it and say why in a comment. + +A third gap is not the analyzer's fault: **`tests/package-consumption/` is not in `DbConnectionPlus.slnx`**, +so `dotnet format` and `dotnet build` on the solution never see it, and its deliberately empty +`Directory.Build.props` means it gets no style gate even when `verify-package-aot.ps1` builds it. If you touch +those files, apply the style by hand. + +## Primary constructor parameters + +Every primary constructor parameter is assigned to a `private readonly` backing field, and members read +`this.field` rather than the parameter: + +```csharp +internal class SqliteEntityManipulator(SqliteDatabaseAdapter databaseAdapter) : IEntityManipulator +{ + private readonly SqliteDatabaseAdapter databaseAdapter = databaseAdapter; +``` + +Using the parameter directly is shorter and looks equivalent. It is not. A parameter that a member body reads +is *captured*, and the field the compiler generates for it carries no `readonly` — so the value becomes +reassignable from inside the type, where the explicit field would have made that a compile error. C# has no way +to mark a primary constructor parameter `readonly`, so the backing field is the only way to keep the guarantee. + +There is no diagnostic for this. `IDE0290` asks for the primary constructor and stops there; the `this.` +rules cannot see a parameter at all. It is on the author. + +The field costs nothing at runtime: a parameter used only in a field initializer is not captured, so the +explicit field and the compiler's capture field are one field, not two. + +## When a tool surprises you + +- **`cleanupcode` re-indents the content of raw string literals and CSharpier puts it back.** Neither is + idempotent alone; the pair is. Always let CSharpier run last — `tidy-cs.ps1` does. +- **Explicit interface implementations sort first — except events.** StyleCop counts an explicit property, + indexer or method as public, so each of those has its own "Explicit interface …" entry in the file layout + putting it at the front of its group. An explicit **event** is counted as private, so it stays where + ReSharper puts it by default, at the end; giving events an entry breaks the build. The entries match + `ImplementsInterface` **and** `Access Is="Private"` — without the access test they would also catch implicit + implementations and pull `Equals(T)` away from `Equals(object)`. +- **Overloads with the same name have no defined order between them.** Two methods called `Equals` tie on + every key the file layout sorts by — kind, access, static, readonly and name — and ReSharper's sort is + stable, so it leaves them in whatever order it found them. Reordering the same file starting from two + different states can therefore give two different results, and both are correct: StyleCop accepts either, + and moving a method declaration changes nothing at runtime. CI does not flap over it, because a stable sort + leaves the committed order alone. There is no fix available — ReSharper's `SortBy` offers `` but + nothing that separates overloads by signature. Put new overloads next to their siblings and it will never + come up. + +## XML documentation comments + +XML docs go on all public and most internal members of the **shipping** projects — ``, ``, +``, ``. Match the density of the file you are editing; `DbConnectionExtensions.QueryFirst.cs` +sets the bar. Invalid XML docs break the docfx workflow. + +The benchmarks are the exception: nothing consumes them as an API, so they use plain `//` comments and switch +`RCS1181` off for that reason. + +## Member order + +StyleCop's order, applied by ReSharper and checked by NewStyleCop. Write a new member straight into the right +place rather than relying on the fixer: + + constants → fields → constructors → finalizers → delegates → events → enums → interfaces + → properties → indexers → conversion operators → operators → methods → nested structs → nested classes + +Within each of those groups: public before internal before protected before private, static before instance, +readonly before mutable, and **alphabetical** after that. + +Note that fields go at the **top** of a type, and that explicit interface implementations sort ahead of the +ordinary methods — with the exception for events described above. + +## Rules the build fully enforces + +These need no attention beyond letting the tools run — they are listed here so that the rule set in AGENTS.md +stays short, not because they are optional: + +- **Primary constructors** wherever `IDE0290` asks for one. +- **Expression-bodied members** are `error`-severity for methods, constructors, operators, properties, indexers, + accessors, lambdas and local functions. Use `=>` wherever a member is a single expression. +- **File-scoped namespaces**, with usings outside the namespace. +- **Max line length is 120**, set once in `.editorconfig` and read from there by CSharpier. Do not wrap lines by + hand — write it on one line and let CSharpier break it. +- Nullable and `ImplicitUsings` are enabled; common namespaces come from `GlobalUsings.cs`. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d59bfe5..96162c2 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -15,4 +15,6 @@ - [ ] Public API changes are declared in the affected `PublicAPI.Unshipped.txt` (`scripts/update-public-api.ps1`). - [ ] XML docs and `README.md` updated for public API changes. - [ ] `CHANGELOG.md` updated, and the version in `src/Directory.Build.props` bumped if this release-bound change needs it. -- [ ] Code formatted (`pwsh -File scripts/format-cs.ps1`). +- [ ] Style, formatting and member ordering applied (`pwsh -File scripts/tidy-cs.ps1 -Scope all`, which + `preflight.ps1` also runs). +- [ ] Branch name follows [Conventional Branch](https://conventionalbranch.org/): `/issue--`. diff --git a/AGENTS.md b/AGENTS.md index c2d8c16..3583628 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,15 +1,14 @@ # AGENTS.md -Guidance for any AI coding agent (Claude Code, Codex, …) working in this repository. This file is the -canonical source; `CLAUDE.md` is a pointer to it plus Claude Code-specific wiring. +Guidance for any AI coding agent (Claude Code, Codex, …) working in this repository. This file is the canonical +source; `CLAUDE.md` is a pointer to it plus Claude Code-specific wiring. ## What this is **DbConnectionPlus** — a lightweight .NET ORM / extension library for `System.Data.Common.DbConnection`. It adds type-safe, high-performance helpers (`Query`, `InsertEntity`, `UpdateEntities`, temporary tables, …) as extension -methods on `DbConnection`, with per-database dialect support supplied by pluggable adapters. - -Published to NuGet as `DbConnectionPlus`; assemblies are named `RentADeveloper.DbConnectionPlus.*`. +methods on `DbConnection`, with per-database dialect support from pluggable adapters. Published to NuGet as +`DbConnectionPlus`; assemblies are named `RentADeveloper.DbConnectionPlus.*`. ## Layout @@ -17,284 +16,181 @@ Published to NuGet as `DbConnectionPlus`; assemblies are named `RentADeveloper.D |---|---| | `src/DbConnectionPlus` | Core library. Root namespace `RentADeveloper.DbConnectionPlus`. | | `src/DbConnectionPlus.DatabaseAdapters.{MySql,Oracle,PostgreSql,Sqlite,SqlServer}` | One adapter project per database system. | -| `tests/DbConnectionPlus.UnitTests` | xUnit v3 unit tests. No database required. | -| `tests/DbConnectionPlus.IntegrationTests` | xUnit v3 integration tests. Requires Docker (see below). | -| `tests/package-consumption/` | Console apps that consume the **packed NuGet packages** rather than project references. `AotConsumer` is published with Native AOT (`scripts/verify-package-aot.ps1`); `AllAdaptersConsumer` installs all six packages and is built by CI on the .NET 8 SDK alone. Not xUnit projects, and deliberately **not** in the solution — see [their README](tests/package-consumption/README.md). | -| `benchmarks/DbConnectionPlus.Benchmarks` | BenchmarkDotNet suite. Everything runs on the JIT; the three entity-mapping categories **also** run as a Native AOT binary. Run it via `scripts/benchmarks.ps1`, and read [its README](benchmarks/DbConnectionPlus.Benchmarks/README.md) before adding a benchmark. | -| `docs/` | docfx config, the site landing page + implementation plans. | -| `.agents/` | Canonical repository skills and review checklists shared by both agent integrations. | -| `.codex/` | Codex custom-agent metadata and PostToolUse hook wiring. | -| `.github/workflows/` | `ci.yml` (lint → build/test/analyze → package + docs → package-consumption gates → publish → release), plus `codeql.yml` and `dependency-review.yml`. | -| `scripts/` | Entry points **you** type: `preflight`, `verify-package-aot`, `benchmarks`, `update-public-api`, `clean-build-artifacts`, `extract-release-notes`. Also `format-cs` and `public-api-guard`, which the editor hooks run for you. | - -Solution file is `DbConnectionPlus.slnx` (the XML `.slnx` format, not `.sln`). **New projects must be added to it.** - -Build properties live in **two** `Directory.Build.props` files, not in the `.csproj` files: - -| File | Applies to | Carries | -|---|---|---| -| `Directory.Build.props` (repo root) | all nine solution projects | `Authors`, `Company`, `Copyright`, `ImplicitUsings`, `LangVersion`, `Nullable`, `TieredCompilation`, and the ErrorProne.NET + Roslynator analyzers | -| `src/Directory.Build.props` | the six shipping projects | ``, `TargetFrameworks=net8.0;net10.0`, `IsAotCompatible`, `AnalysisLevel=latest-all`, `TreatWarningsAsErrors`, the AOT and public-API analyzers, the NuGet package metadata, and the files every package carries | - -MSBuild uses the **nearest** `Directory.Build.props` and stops, so `src/Directory.Build.props` imports the root -one explicitly — remove that import and the six shipping projects silently lose authorship, nullability and the -style analyzers. The split exists because `tests/` and `benchmarks/` set neither `TreatWarningsAsErrors` nor -`AnalysisLevel` and would newly break under them. (The benchmarks are `net10.0` — BenchmarkDotNet's -`NativeAotToolchain.Net10_0` publishes that TFM. The **unit tests multi-target `net8.0;net10.0`**, because the -two builds of the shipping libraries are not the same code — `net8.0` carries an `IL3050` suppression -`net10.0` does not. The integration tests stay `net8.0`: they are bound by four database containers rather -than by the runtime, and doubling a ten-minute suite buys nothing the unit tests do not already cover on both.) - -`tests/package-consumption/` sits **outside** all of this on purpose: it carries its own empty -`Directory.Build.props`/`.targets` that stop MSBuild's upward search, so those projects receive the library -only from the packed packages. Do not "fix" that by deleting the empty files. - -What stays in a `.csproj` is per-project identity — `AssemblyName`, `AssemblyTitle`, `RootNamespace`, -`PackageId`, `Description`, `PackageTags` — plus that project's own package references. A shipping `.csproj` is -about 20 lines. The package icon is **one** file, `assets/logo-128.png`, referenced from -`src/Directory.Build.props` for all six packages. - -**Two readmes, and they are not interchangeable.** `README.md` is the repository's reference documentation and what a GitHub visitor reads. `PACKAGE_README.md` is what nuget.org renders as the package -page: a short overview for someone deciding whether to install, which links back to the long one. Both ship -from the repo root; only `PACKAGE_README.md` goes into the packages. An API change updates `README.md`; touch -`PACKAGE_README.md` only when the overview itself stops being true. +| `tests/DbConnectionPlus.{Unit,Integration}Tests` | The two xUnit v3 suites. The unit tests need no database; the integration tests need Docker. | +| `tests/package-consumption/` | Console apps that consume the **packed NuGet packages** instead of project references. Deliberately **not** in the solution — [their README](tests/package-consumption/README.md). | +| `benchmarks/DbConnectionPlus.Benchmarks` | BenchmarkDotNet suite, run via `scripts/benchmarks.ps1`. Read [its README](benchmarks/DbConnectionPlus.Benchmarks/README.md) before adding a benchmark. | +| `docs/` | docfx config, the site landing page and implementation plans. | +| `.agents/`, `.codex/`, `.claude/` | Canonical skills and references, plus each tool's agent metadata and hook wiring. | +| `.github/workflows/` | `ci.yml` (lint → build/test → package + docs → package-consumption gates → publish), `codeql.yml`, `dependency-review.yml`. | +| `scripts/` | The commands you type: `preflight`, `verify-package-aot`, `benchmarks`, `update-public-api`, `clean-build-artifacts`, `extract-release-notes`. Plus `tidy-cs` and `public-api-guard`, which the editor hooks run for you. | + +The solution file is `DbConnectionPlus.slnx` (XML `.slnx`, not `.sln`). **New projects must be added to it.** + +Build properties live in two `Directory.Build.props` files, not in the `.csproj` files: the repo-root one for all +nine solution projects (shared metadata, and the **style gate** — `EnforceCodeStyleInBuild` + +`TreatWarningsAsErrors`), and `src/Directory.Build.props` for the six shipping projects (``, +`TargetFrameworks`, `IsAotCompatible`, `AnalysisLevel=latest-all`, the AOT and public-API analyzers, the package +metadata). The `src/` one imports the root explicitly, because MSBuild stops at the nearest file, and it is where +`AnalysisLevel=latest-all` has to stay — CA1707 alone objects 2100 times to the test suite's +`Method_ShouldDoSomething` naming. Target frameworks differ per project on purpose: benchmarks `net10.0`, unit +tests `net8.0;net10.0` (the shipping libraries' two builds are not the same code), integration tests `net8.0`. + +`tests/package-consumption/` sits **outside** all of this on purpose. It carries its own empty +`Directory.Build.props`/`.targets` that stop MSBuild's upward search, so those projects get the library only from +the packed packages. Do not "fix" that by deleting the empty files. + +**Two readmes, and they are not interchangeable.** `README.md` is the repository's reference documentation, what a +GitHub visitor reads, and what an API change updates. `PACKAGE_README.md` is the short overview nuget.org renders +as the package page: it links back to the long one, it is the only one that ships inside the packages, and you +touch it only when the overview itself stops being true. ### The adapter seam `IDatabaseAdapter` (`src/DbConnectionPlus/DatabaseAdapters/IDatabaseAdapter.cs`) exposes `IEntityManipulator` and -`ITemporaryTableBuilder`. Each of the five adapter projects implements all three: +`ITemporaryTableBuilder`, and each of the five adapter projects implements all three. -``` -{Db}DatabaseAdapter.cs {Db}EntityManipulator.cs -{Db}TemporaryTableBuilder.cs {Db}ConfigurationExtensions.cs -``` - -**A change to one adapter almost always needs mirroring into the other four.** Only the integration suite catches a -miss, and that needs Docker. Use the `adapter_parity_reviewer` Codex custom agent, walk +**A change to one adapter almost always needs mirroring into the other four.** Only the integration suite catches +a miss, and that needs Docker. Run the adapter-parity reviewer, walk [its checklist](.agents/references/reviews/adapter-parity.md) over the diff, or check the other four by hand. -Core marks internals visible to all five adapters and to the test/benchmark assemblies -(`src/DbConnectionPlus/AssemblyAttributes.cs`). - ## Build & test ```bash dotnet build DbConnectionPlus.slnx -c Release -``` - -```bash dotnet test --project tests/DbConnectionPlus.UnitTests/DbConnectionPlus.UnitTests.csproj +pwsh -File scripts/preflight.ps1 # both, plus hygiene and tidying — the default loop +pwsh -File scripts/verify-package-aot.ps1 -Pack # the Native AOT gate ``` -Both, plus the repo-hygiene checks, in one command: - -```bash -pwsh -File scripts/preflight.ps1 -``` - -The Native AOT gate — packs the six projects, publishes `tests/package-consumption/AotConsumer` natively -**from the packages**, gates its IL diagnostics and runs the binary. It is the **only** check that can see -silent trimming damage, because nothing is trimmed on the JIT. Needs a C++ toolchain: MSVC on Windows, -`clang` + `zlib1g-dev` on Linux. - -```bash -pwsh -File scripts/verify-package-aot.ps1 -Pack -``` - -Run it when you change reflection, DAM annotations, the materializers or the temp-table readers. It is not part -of `preflight.ps1` — a pack plus a native publish takes minutes. `-Framework net8.0` checks the documented AOT -floor, which behaves differently from the `net10.0` default; CI runs both. Drop `-Pack` to reuse the packages -already in `artifacts/packages`. - -It consumes packages rather than projects because the annotations, the embedded `ILLink.Descriptors.xml` and -the `IsTrimmable` marker all have to survive `dotnet pack` — a project-referenced version of this check would -stay green if packing dropped every one of them. - -Integration tests need a running Docker daemon and nothing else — no container to start by hand, no connection -string to configure: - -```bash -dotnet test --project tests/DbConnectionPlus.IntegrationTests/DbConnectionPlus.IntegrationTests.csproj -``` - -[Testcontainers](https://dotnet.testcontainers.org/) owns the databases. The container definitions live in -`tests/DbConnectionPlus.IntegrationTests/TestDatabase/Containers/`, one fixture per database system, and each one -builds its own connection string from the free host port its container was published on — which is why nothing -collides with a locally installed server and why there is no port to agree on with CI. Containers start **lazily, -per database system**: a run filtered to SQLite and SQL Server never starts the MySQL, Oracle or PostgreSQL -container, and SQLite needs none at all. They are removed when the run ends, so every run starts from a clean -server and pays for the startup — 5 to 24 seconds each, Oracle being the slow one. Details, measured timings and -what to do when a container will not start: [the `integration-db` skill](.agents/skills/integration-db/SKILL.md). - -**Scope the run.** The integration suite is not part of the default verification loop — `scripts/preflight.ps1` -is. Run it when a change can only be proven against a real database, and when you do, the default scope is -**SQLite + SQL Server** (~90 s, versus ~600 s for all five). Add another adapter's tests **only if you changed -that adapter's code**; run all five only for a change to `IDatabaseAdapter`, `IEntityManipulator` or -`ITemporaryTableBuilder`, which all five implement. Rules and measured timings: -[the `integration-db` skill](.agents/skills/integration-db/SKILL.md). - -## Code style — the build enforces this - -`TreatWarningsAsErrors=true` with `AnalysisLevel=latest-all`, `EnforceCodeStyleInBuild=true`, ErrorProne.NET, and -Roslynator's entire category at `error`. A style slip is a build break, not a warning. - -- **BCL type names, PascalCase**: write `String`, `Object?`, `Int32`, `Boolean` — *not* `string`, `object`, `int`, - `bool`. (`dotnet_style_predefined_type_for_*` is `false`.) -- **Expression-bodied members are `error`-severity** for methods, constructors, operators, properties, indexers, - accessors, lambdas and local functions. Use `=>` wherever a member is a single expression. -- **File-scoped namespaces** and usings outside the namespace. -- **Max line length** is **120**. -- **No UTF-8 BOM.** `.editorconfig` sets `charset = utf-8` for `*.cs`. That is the whole rule: editors honour - it when they write a file, and CI's `dotnet format whitespace --verify-no-changes` fails a BOM'd file as - `error CHARSET`. Git cannot help — it treats a BOM as content — so that lint - step is the gate. To fix one, run `pwsh -File scripts/format-cs.ps1 -Scope all` (or `-Scope whitespace`); - the default `style` scope does not apply the charset fixer. It matters because a BOM read as plain UTF-8 - becomes an invisible U+FEFF on the first token, which silently breaks anchored edits. -- **Copyright header** on every new `.cs` file: - ```csharp - // Copyright (c) 2026 David Liebeherr - // Licensed under the MIT License. See LICENSE.md in the project root for more information. - ``` -- **XML docs** on all public and most internal members of the **shipping** projects — ``, ``, - ``, ``. Match the density of the file you are editing; `DbConnectionExtensions.QueryFirst.cs` - sets the bar. Invalid XML docs break the docfx workflow. The benchmarks are the exception: nothing consumes - them as an API, so they use plain `//` comments and switch `RCS1181` off for that reason. +Search the **whole repository** when a change touches a shared symbol. A search scoped to `src/` will miss call +sites in `tests/` and `benchmarks/`; `EntityHelper.GetEntityTypeMetadata`, for scale, is used in 18 files across +eight projects. The Release build covers every project, so it turns a missed call site into a build error. + +The Native AOT gate is the **only** check that can see silent trimming damage, because nothing is trimmed on the +JIT. Run it whenever you change reflection, DAM annotations, the materializers or the temp-table readers. It packs +the six projects, publishes `AotConsumer` natively **from the packages**, gates its IL diagnostics and runs the +binary. It needs a C++ toolchain and minutes, so it is not in `preflight.ps1`; `-Framework net8.0` checks the +documented AOT floor, and CI runs that as well as the `net10.0` default. + +Integration tests need only a running Docker daemon; [Testcontainers](https://dotnet.testcontainers.org/) starts a +container per database system and removes it afterwards. **Scope the run:** the default is **SQLite + SQL Server** +(~90 s, against ~600 s for all five); add another adapter's tests **only if you changed that adapter's code**; run +all five only for a change to `IDatabaseAdapter`, `IEntityManipulator` or `ITemporaryTableBuilder`. Commands, +timings and troubleshooting: [the `integration-db` skill](.agents/skills/integration-db/SKILL.md). + +## Code style, formatting and ordering + +Formatting is CSharpier's, style is the Roslyn analyzers', ordering is ReSharper's and NewStyleCop's. All three are +build errors, in `tests/` and `benchmarks/` as much as in `src/`. Details, and the three cases where a tool does +something surprising: [the code-style reference](.agents/references/code-style.md). + +- **C# keywords, never BCL type names**: `string`, `object?`, `int`, `bool`, `nint`, `nuint` — not `String`, + `Object?`, `Int32`, `Boolean`, `IntPtr`, `UIntPtr`. ⚠️ **The build does not catch all of this.** `IDE0049` + ignores `nint`/`nuint` and never looks inside `nameof(...)`, and `tests/package-consumption/` has no style gate + at all. Apply the rule by hand in those three places — reasons in + [the reference](.agents/references/code-style.md#where-the-build-misses-a-bcl-type-name). +- **Always `this.`** for instance fields, properties, methods and events; fields are never `_camelCase` (`SA1309`). + A **primary constructor parameter** is assigned to a `private readonly` backing field and read through + `this.field` — never used directly in a member body. ⚠️ **The build does not catch this.** A captured parameter + compiles to a field with no `readonly`, so using one directly silently drops the guarantee that the value cannot + be reassigned — [why it matters](.agents/references/code-style.md#primary-constructor-parameters). +- **Member order** is StyleCop's: constants and fields at the **top** of a type, then constructors, finalizers, + delegates, events, enums, interfaces, properties, indexers, operators, methods, nested types; within each group + public before private, static before instance, readonly before mutable, then alphabetical. Write a new member + into the right place instead of relying on the fixer — [full order](.agents/references/code-style.md#member-order). - **Resolve analyzer diagnostics, don't suppress.** If a suppression is unavoidable use a scoped `#pragma` with a comment, matching the `#pragma warning disable CA1710` style in `Dynamic/DataRow.cs`. ⚠️ **An `IL2xxx` trim warning is not yours to suppress.** They are the only build-time proof that the `[DynamicallyAccessedMembers]` chain is complete, and an incomplete chain means silently unpopulated entities - under trimming. The library has exactly two sanctioned `IL2xxx` suppressions — `IL2060` in - `MaterializerFactoryHelper` and `IL2065` in `ValueTupleMaterializerFactory` — each narrow, justified in place - and backed by a test; a third one is a finding. Never suppress one at a public API. -- Nullable and `ImplicitUsings` are enabled; common namespaces come from `GlobalUsings.cs`. - -**Format edited `.cs` files before building** — it is much cheaper than discovering a style break in the build: + under trimming. Exactly two are sanctioned, both narrow and backed by a test: `IL2060` in + `MaterializerFactoryHelper`, `IL2065` in `ValueTupleMaterializerFactory`. A third is a finding, and never + suppress one at a public API. +- **No C# 14 extension member syntax** until docfx [supports it](https://github.com/dotnet/docfx/issues/10808). +- **No UTF-8 BOM** (`.editorconfig` sets `charset = utf-8` for `*.cs`). A BOM read as plain UTF-8 becomes an + invisible U+FEFF on the first token, which silently breaks anchored edits. +- **Copyright header** on every new `.cs` file — copy the `// Copyright (c) 2026 David Liebeherr` and + `// Licensed under the MIT License. …` pair from an existing file. +- **XML docs** on all public and most internal members of the **shipping** projects; invalid ones break the docfx + workflow, and benchmarks are exempt. [Details](.agents/references/code-style.md#xml-documentation-comments). +- Primary constructors, `=>` for single-expression members, file-scoped namespaces, the 120-column limit, nullable + and `ImplicitUsings` — [the build fully enforces these](.agents/references/code-style.md#rules-the-build-fully-enforces). + +One entry point applies all of it, in three scopes: ```bash -pwsh -File scripts/format-cs.ps1 +pwsh -File scripts/tidy-cs.ps1 # ~1s formatting, on the files git reports as changed +pwsh -File scripts/tidy-cs.ps1 -Scope style # ~15s + the code-style fixers +pwsh -File scripts/tidy-cs.ps1 -Scope all # ~3min + member ordering, whole solution ``` -With no arguments that formats every `.cs` file git reports as changed; pass paths to format specific files. -Claude Code and Codex both run it automatically on every edit via a PostToolUse hook, so under either agent it -is already done — see [.agents/README.md](.agents/README.md) for the wiring, and note that Codex only runs -project-local hooks after you have trusted them with `/hooks`. +**Before you commit, run `-Scope all`** — or `scripts/preflight.ps1`, which does it for you. That is the only scope +that reorders members, because ReSharper loads the whole solution either way. Claude Code and Codex run the +**default scope** on every `.cs` edit through a PostToolUse hook; style and ordering are not run there, because +they are too slow for a single edit and the build catches them. ## Tests -xUnit v3 with `[Fact]` / `[Theory]`, assertions via **AwesomeAssertions** (`.Should()`, `Invoking(…)`), fakes via -**NSubstitute** (plus `NSubstitute.Community.DbConnection` for `DbConnection`/`DbDataReader`), data via -**AutoFixture**, **Bogus** and **Mapster**, and null-guard coverage via **RentADeveloper.ArgumentNullGuards**. - -- Naming: `Method_Scenario_ShouldExpectedOutcome`. -- Tests derive from `UnitTestsBase` / `IntegrationTestsBase`. -- One test file per public method, mirroring the `DbConnectionExtensions.*.cs` split. - -### The declared public API +xUnit v3 with `[Fact]` / `[Theory]`, assertions via **AwesomeAssertions**, fakes via **NSubstitute** (plus +`NSubstitute.Community.DbConnection`), data via **AutoFixture**, **Bogus** and **Mapster**, null-guard coverage via +**RentADeveloper.ArgumentNullGuards**. Name tests `Method_Scenario_ShouldExpectedOutcome`, derive them from +`UnitTestsBase` / `IntegrationTestsBase`, one test file per public method, mirroring `DbConnectionExtensions.*.cs`. -Each of the **six shipping projects** declares its public surface in two files next to its `.csproj`: +## The declared public API -| File | Contains | -|---|---| -| `PublicAPI.Shipped.txt` | everything that shipped in the last release. Starts with `#nullable enable`, so `string!` and `string?` are different entries. | -| `PublicAPI.Unshipped.txt` | what is new since then, and `*REMOVED*` lines for what is gone. | - -`Microsoft.CodeAnalysis.PublicApiAnalyzers` (wired in `src/Directory.Build.props`) enforces them **at build -time**: a public member that is not declared is `RS0016`, one that is declared but no longer exists is -`RS0017`. With `TreatWarningsAsErrors=true` both are build errors, so an accidental change to the public -surface cannot compile — in an adapter as much as in core. - -A deliberate change means recording it: - -```bash -pwsh -File scripts/update-public-api.ps1 -``` - -That applies the `RS0016` fix, writing the new entries into `PublicAPI.Unshipped.txt` (and creating the two -files for a project that has none — `dotnet format` will not). **Review the diff**: it is the public-API -change, and per [CONTRIBUTING.md](CONTRIBUTING.md) it also requires a `CHANGELOG.md` entry, a `README.md` -update and a SemVer bump in `src/Directory.Build.props`. A `*REMOVED*` line is a break. - -At release time, `pwsh -File scripts/update-public-api.ps1 -MarkShipped` folds `Unshipped` into `Shipped`, so -the next release's `Unshipped.txt` again means "new since the last one". - -## Cross-project work: search the whole repo - -Changes routinely touch the same symbol across the nine projects in the solution. A search scoped to `src/` -**will** miss call sites in `tests/` and `benchmarks/` that must be updated in the same change. For scale: -`EntityHelper.GetEntityTypeMetadata` is used in 18 files spread over eight projects, and the benchmark project -compiles against the same public surface as the tests do. If a search over a widely used symbol returns a -handful of hits, suspect the search before believing the count. - -Search the whole repository with ripgrep, and let the compiler confirm: `dotnet build DbConnectionPlus.slnx -c -Release` builds every project, so a call site the search missed is a build error rather than a surprise later. +Each of the six shipping projects declares its public surface next to its `.csproj`, in `PublicAPI.Shipped.txt` +(what shipped in the last release) and `PublicAPI.Unshipped.txt` (what is new since, plus `*REMOVED*` +lines for what is gone). `Microsoft.CodeAnalysis.PublicApiAnalyzers` enforces them **at build time**: `RS0016` for +an undeclared public member, `RS0017` for a declared one that is gone, both errors, so an accidental change to the +public surface cannot compile. Record a deliberate one with `pwsh -File scripts/update-public-api.ps1`, then +**review the diff**: it is the public-API change. Per +[CONTRIBUTING.md](CONTRIBUTING.md) it also needs a `CHANGELOG.md` entry, a `README.md` update and a SemVer bump in +`src/Directory.Build.props`. A `*REMOVED*` line is a break. `-MarkShipped` folds `Unshipped` into `Shipped` at +release time. ## Native AOT support -The **reflection paths are AOT-safe**: no companion package, no source generator, no consumer opt-in. AOT users -reference DbConnectionPlus and publish. - -- Runtime *code generation* is what Native AOT forbids — plain reflection is fine. So accessors go through - `System.Reflection.MethodInvoker` and complex-object temporary tables through `EnumerableReader`, both single - path; the expression-compiled materializer is the JIT fast path only, behind a - `RuntimeFeature.IsDynamicCodeSupported` branch that the AOT compiler folds away. Do not introduce a - dependency that emits IL (`Fasterflect`, `FastMember` and friends) — it would be invisible to the analyzers - and break every AOT consumer. -- ⚠️ **Correctness constraint:** under trimming, missing `[DynamicallyAccessedMembers]` annotations make - reflection return *fewer members with no error* — measured: 6 columns in, 0 bound, no exception. Three - layers defend this: DAM annotations, **treating an `IL2xxx` warning as a defect rather than as noise to - suppress** (see the code-style section for the two sanctioned exceptions), and a zero-binding guard. - The defect is invisible on the JIT, so **only `scripts/verify-package-aot.ps1` catches it** — run it after - any change to a reflection path. -- The generic query methods carry **neither** `[RequiresUnreferencedCode]` nor `[RequiresDynamicCode]`, so a - consumer publishing with `PublishAot` or `PublishTrimmed` sees no diagnostic at a call site. The three - reflection sites the analyzers report inside the library are answered where they occur — the argument is in - [No consumer-facing diagnostics](DESIGN-DECISIONS.md#4-no-consumer-facing-diagnostics). Adding either - attribute to a public API is a regression the AOT consumer's zero-diagnostic gate fails on. - -A source-generator design was prototyped, benchmarked and **rejected**. Rationale, measurements and the full -design record: [DESIGN-DECISIONS.md](DESIGN-DECISIONS.md#native-aot-and-trimming). Do not reintroduce it. - -Before changing anything that reflects, use the `aot_compat_reviewer` Codex custom agent or walk -[its checklist](.agents/references/reviews/aot-compat.md). +The **reflection paths are AOT-safe**: no companion package, no source generator, no consumer opt-in. Rationale and +measurements: [DESIGN-DECISIONS.md](DESIGN-DECISIONS.md#native-aot-and-trimming). Before changing anything that +reflects, run the AOT/trim reviewer or walk [its checklist](.agents/references/reviews/aot-compat.md). Three +constraints must not be broken: + +- **Nothing may generate code at run time** — that, not reflection, is what Native AOT forbids. Accessors use + `System.Reflection.MethodInvoker`, complex-object temporary tables use `EnumerableReader`, and the + expression-compiled materializer sits behind a `RuntimeFeature.IsDynamicCodeSupported` branch the AOT compiler + folds away. Add no IL-emitting dependency, and do not reintroduce the prototyped-and-rejected source generator. +- ⚠️ **The `[DynamicallyAccessedMembers]` chain must stay complete.** Under trimming a missing annotation makes + reflection return *fewer members with no error* — measured: 6 columns in, 0 bound, no exception. It is invisible + on the JIT, so **only `scripts/verify-package-aot.ps1` catches it**. That is why an `IL2xxx` warning is never + suppressed; the code-style rules name the two sanctioned exceptions. +- **No consumer-facing diagnostics.** The generic query methods carry neither `[RequiresUnreferencedCode]` nor + `[RequiresDynamicCode]`; adding either to a public API is a regression the AOT consumer's zero-diagnostic gate + fails on. The argument: [DESIGN-DECISIONS.md](DESIGN-DECISIONS.md#4-no-consumer-facing-diagnostics). ## Conventions -- Branches: `feature/-` or `bugfix/-`, PR'd into `main`. +- Branches: [Conventional Branch](https://conventionalbranch.org/) — `/issue--` off `main`, + types `feature/ bugfix/ hotfix/ release/ chore/`. An agent on its own branch may use `claude/` or `codex/`. - Commits: Conventional Commits — `feat:`, `fix:`, `BREAKING CHANGE:`. Full checklist: - [the `commit` skill](.agents/skills/commit/SKILL.md). -- `CHANGELOG.md` follows [Keep a Changelog](https://keepachangelog.com/); versioning is SemVer. + [the `commit` skill](.agents/skills/commit/SKILL.md). `CHANGELOG.md` follows + [Keep a Changelog](https://keepachangelog.com/); versioning is SemVer. +- Pull request process: [CONTRIBUTING.md](CONTRIBUTING.md#pull-request-process). ### Releases -**Never `dotnet pack` and push by hand.** A release is a pushed tag, and CI does the rest: - -1. Bump `` in `src/Directory.Build.props` — the single source of truth for all six packages. -2. Give the `CHANGELOG.md` section a real date: `## [4.1.0] - 2026-08-17`. Not `TBD`, not empty — CI reads - this section, uses it as the release notes, and refuses to publish without it. -3. Merge to `main`, then push the matching tag: `git tag v4.1.0 && git push origin v4.1.0`. - -`ci.yml` then verifies the tag against the packed version, publishes all six packages to NuGet.org, and -creates the GitHub release with the changelog section and the packages attached. Nothing reaches NuGet.org -that has not passed the lint, test, Native AOT and .NET 8 consumer gates first. A tag whose version does not -match `src/Directory.Build.props` fails the publish job rather than shipping stale packages. +**Never `dotnet pack` and push by hand.** A release is a pushed tag and CI does the rest: it checks the tag against +the packed version, publishes all six packages to NuGet.org, and creates the GitHub release from the `CHANGELOG.md` +section. The three steps: [CONTRIBUTING.md](CONTRIBUTING.md#releasing). ## Working procedures -Native Codex skills and custom agents are checked into the repository — see -[.agents/README.md](.agents/README.md) for the layout and Claude Code compatibility wrappers. - -| Task | Codex | Claude Code | -|---|---|---| -| Commit changes | `$commit` | `/commit` | -| Run the integration DBs | `$integration-db` | `/integration-db` | -| Review AOT/trim safety | `aot_compat_reviewer` custom agent | `aot-compat-reviewer` subagent | -| Review adapter parity | `adapter_parity_reviewer` custom agent | `adapter-parity-reviewer` subagent | +Two skills and two review agents are checked in, each under a Codex and a Claude name: `$commit` / `/commit`, +`$integration-db` / `/integration-db`, `aot_compat_reviewer` / `aot-compat-reviewer`, `adapter_parity_reviewer` / +`adapter-parity-reviewer`. -Claude Code (`.claude/settings.json`) and Codex (`.codex/hooks.json`) both fire the same two PostToolUse hooks — -formatting and the public-API reminder — and both delegate to `scripts/`. Codex needs those hooks trusted once -per clone (`/hooks`); until then nothing fires and you run `scripts/format-cs.ps1` yourself. -`scripts/preflight.ps1` before committing is on you under every agent. +Claude Code (`.claude/settings.json`) and Codex (`.codex/hooks.json`) fire the same two PostToolUse hooks — +formatting and the public-API reminder — and both delegate to `scripts/`. Codex needs those hooks trusted once per +clone (`/hooks`); until then nothing fires and you run `scripts/tidy-cs.ps1` yourself. -Keep reusable skills and review checklists in `.agents/`, Codex metadata and hook wiring in `.codex/`, Claude -Code metadata and hook wiring in `.claude/`, and executable checks in `scripts/`. Do not fork a procedure or -check into a tool-specific copy — both integrations must follow the same canonical instructions and scripts. +Reusable skills and reference material belong in `.agents/`, executable checks in `scripts/`, and only metadata and +hook wiring in `.codex/` and `.claude/`. Never fork a procedure or a check into a tool-specific copy — both +integrations follow the same canonical files. Layout: [.agents/README.md](.agents/README.md). diff --git a/CLAUDE.md b/CLAUDE.md index dd35cd1..8b6907f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,11 +1,5 @@ # CLAUDE.md -Read [AGENTS.md](AGENTS.md) first. It is the canonical repository guidance and everything in it applies to -Claude Code. +Read [AGENTS.md](AGENTS.md) first — it is the canonical guidance, and all of it applies to Claude Code. -The files under `.claude/skills/` and `.claude/agents/` contain only Claude Code discovery metadata and point -to their shared procedures under `.agents/`. Keep reusable instructions in those shared files, not here or in -the wrappers. - -`.claude/settings.json` wires the PostToolUse adapters under `.claude/hooks/` to the canonical implementations -in `scripts/`. Change hook behavior in `scripts/`; keep `.claude/hooks/` limited to Claude's hook protocol. +`.claude/` holds only discovery metadata and hook adapters; the procedures live in `.agents/` and `scripts/`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1e40540..49efa35 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,16 +7,28 @@ Please note we have a code of conduct, please follow it in all your interactions ## Pull Request Process -1. Branch from `main` as `feature/-` or `bugfix/-`, and use - [Conventional Commits](https://www.conventionalcommits.org/) for the messages. +1. Branch from `main` following [Conventional Branch](https://conventionalbranch.org/): + `/`, or `/issue--` when there is an issue — for example + `feature/issue-42-bulk-insert`. The types are `feature/`, `bugfix/`, `hotfix/`, `release/` and + `chore/`; use the long forms, not `feat/` or `fix/`. Descriptions are lowercase letters, digits and + hyphens, with no hyphen at the start or end and never two in a row. An AI agent working on its own + branch may use `claude/` or `codex/` in place of a type. + + Use [Conventional Commits](https://www.conventionalcommits.org/) for the messages. 2. Make the change, with tests. New behavior and fixed bugs need coverage; a change to one database adapter almost always has to be mirrored into the other four. -3. Run the pre-commit gate. It formats, builds and runs the unit suite: +3. Run the pre-commit gate. It applies style, formatting and member ordering, then builds and runs the + unit suite: ```shell pwsh -File scripts/preflight.ps1 ``` - `TreatWarningsAsErrors` is on for the six shipping projects, so the build is also the style, trim-analyzer - and public-API gate. **Never suppress an `IL2xxx` warning to get a green build** — it is the only + It rewrites files — review what it changed and include it in your commit. To run just the tidying: + `pwsh -File scripts/tidy-cs.ps1 -Scope all`. + + `TreatWarningsAsErrors` is on for **every** project, so the build is also the style, member-ordering, + trim-analyzer and public-API gate, and `CSharpier.MsBuild` makes an unformatted file a build error too. + The build never rewrites your files — it fails and names them; `scripts/tidy-cs.ps1` is what fixes them. + **Never suppress an `IL2xxx` warning to get a green build** — it is the only build-time evidence that the trimming annotations are complete. 4. If you touched a reflection path, also run the Native AOT gate. Nothing else in the repository can see silent trimming damage: @@ -36,6 +48,24 @@ Please note we have a code of conduct, please follow it in all your interactions The full working guide — layout, the adapter seam, code style, the declared public API and Native AOT — is [AGENTS.md](AGENTS.md). It is written for AI coding agents, but everything in it applies to people too. +## Setting up a clone + +Two things to do once, after cloning: + +```shell +dotnet tool restore +git config blame.ignoreRevsFile .git-blame-ignore-revs +``` + +The first installs CSharpier, the ReSharper command line tools and docfx, which `scripts/tidy-cs.ps1` and the +documentation build need. The second makes `git blame` skip the commits listed in `.git-blame-ignore-revs`, +which reformatted and reordered the whole repository, so blame points at whoever wrote the logic rather than +at the tool that moved it. GitHub already does this on its own. + +If you use Rider, two settings make the tooling invisible: install the **CSharpier** plugin and switch on +Settings | Tools | CSharpier | Run on Save, and use the shared **ReorderMembers** cleanup profile (from +`DbConnectionPlus.slnx.DotSettings`) when you want members put back in order. + ## Releasing Releases are cut by CI from a pushed tag; nothing is packed or pushed by hand. The versioning scheme is From bf166913950f5f49ca53b5046c93c67f336beae5 Mon Sep 17 00:00:00 2001 From: David Liebeherr Date: Thu, 27 Aug 2026 06:58:54 +0200 Subject: [PATCH 12/12] chore: point .git-blame-ignore-revs at the five mechanical commits Last commit on the branch by necessity: it names commits by SHA, so they have to exist first. Part of #21 Co-Authored-By: Claude Opus 5 --- .git-blame-ignore-revs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000..36e29a5 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,39 @@ +# Commits that rewrote lines across most of the repository without changing what the code does. +# `git blame` skips them, so it points at whoever wrote the logic rather than at the tool that +# reformatted it. +# +# GitHub reads this file automatically. Locally you have to opt in, once per clone: +# +# git config blame.ignoreRevsFile .git-blame-ignore-revs +# +# Add a commit here when its effect on SOURCE files is entirely tool output. A commit that also carries +# hand-written configuration or documentation still qualifies - blame on the code is what this file is +# protecting - but say so in its note. +# +# The SHAs below are load-bearing, and git does NOT warn about one it cannot resolve: it skips the entry, +# and blame quietly goes back to pointing at the tool. "Rebase and merge" and "Squash and merge" rewrite +# every SHA on a branch, so merge a branch that adds an entry here with a MERGE COMMIT. CI's lint job +# fails if any revision below stops resolving, which is what turns that mistake into something visible. + +# style: use C# keywords instead of BCL type names +# dotnet format style --diagnostics IDE0049. 207 files. +89bc6d82d1dcb8033083af45553d32d06cbc6fd8 + +# style: convert eligible constructors to primary constructors +# dotnet format style --diagnostics IDE0290, six sites. MIXED: also removes 23 stale +# "Initializes a new instance" doc lines the fixer leaves behind. +3c4793070f06013f6bfe28cf1b921b464e845e45 + +# style: reformat every C# file with CSharpier +# csharpier format . - the first run, after which nobody places a line break by hand. +f80b2f75fa4a8331c1b63aef1686144560d1e904 + +# style: reorder type members into StyleCop order +# jb cleanupcode --profile=ReorderMembers, then csharpier. Fields moved to the top of each type. +48c97d6088a601ee461bf0546150f4672b47f471 + +# style: satisfy the gates the previous commit turned on +# dotnet format (IDE0005, RCS1250) and jb cleanupcode. MIXED: the keyword conversions under +# tests/package-consumption/ and the MySql primary constructor were applied by hand, because no tool +# in the pipeline reaches them. +70f9ea67d055d9932c1ff9f5bf3204af9e1c78c4