From 56a8d9ffe16ebb1393484d13f3eeb1c30d281f7a Mon Sep 17 00:00:00 2001 From: Takaaki Suzuki Date: Wed, 10 Nov 2021 22:19:59 +0900 Subject: [PATCH 01/10] Enable C# 10.0 --- .../DeclarativeSql.MicrosoftSqlClient.csproj | 2 +- .../DeclarativeSql.SystemSqlClient.csproj | 2 +- src/DeclarativeSql.Tests/DeclarativeSql.Tests.csproj | 2 +- src/DeclarativeSql/DeclarativeSql.csproj | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/DeclarativeSql.MicrosoftSqlClient/DeclarativeSql.MicrosoftSqlClient.csproj b/src/DeclarativeSql.MicrosoftSqlClient/DeclarativeSql.MicrosoftSqlClient.csproj index 91c329e..459b175 100644 --- a/src/DeclarativeSql.MicrosoftSqlClient/DeclarativeSql.MicrosoftSqlClient.csproj +++ b/src/DeclarativeSql.MicrosoftSqlClient/DeclarativeSql.MicrosoftSqlClient.csproj @@ -3,7 +3,7 @@ netstandard2.0;netstandard2.1;net461;net5 DeclarativeSql - 9.0 + 10.0 enable true diff --git a/src/DeclarativeSql.SystemSqlClient/DeclarativeSql.SystemSqlClient.csproj b/src/DeclarativeSql.SystemSqlClient/DeclarativeSql.SystemSqlClient.csproj index 11ad438..29d94ba 100644 --- a/src/DeclarativeSql.SystemSqlClient/DeclarativeSql.SystemSqlClient.csproj +++ b/src/DeclarativeSql.SystemSqlClient/DeclarativeSql.SystemSqlClient.csproj @@ -3,7 +3,7 @@ netstandard2.0;netstandard2.1;net461;net5 DeclarativeSql - 9.0 + 10.0 enable true diff --git a/src/DeclarativeSql.Tests/DeclarativeSql.Tests.csproj b/src/DeclarativeSql.Tests/DeclarativeSql.Tests.csproj index 6070fbb..c32a064 100644 --- a/src/DeclarativeSql.Tests/DeclarativeSql.Tests.csproj +++ b/src/DeclarativeSql.Tests/DeclarativeSql.Tests.csproj @@ -2,7 +2,7 @@ net5 - 9.0 + 10.0 enable diff --git a/src/DeclarativeSql/DeclarativeSql.csproj b/src/DeclarativeSql/DeclarativeSql.csproj index b063064..db433ed 100644 --- a/src/DeclarativeSql/DeclarativeSql.csproj +++ b/src/DeclarativeSql/DeclarativeSql.csproj @@ -2,7 +2,7 @@ netstandard2.0;netstandard2.1;net461;net5 - 9.0 + 10.0 enable true true From 00272e7bb0bda40391802cd1f4f97e17ebafdf3b Mon Sep 17 00:00:00 2001 From: Takaaki Suzuki Date: Wed, 10 Nov 2021 22:23:11 +0900 Subject: [PATCH 02/10] Supports .NET 6 --- .../DeclarativeSql.MicrosoftSqlClient.csproj | 2 +- .../DeclarativeSql.SystemSqlClient.csproj | 2 +- src/DeclarativeSql.Tests/DeclarativeSql.Tests.csproj | 2 +- src/DeclarativeSql/DeclarativeSql.csproj | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/DeclarativeSql.MicrosoftSqlClient/DeclarativeSql.MicrosoftSqlClient.csproj b/src/DeclarativeSql.MicrosoftSqlClient/DeclarativeSql.MicrosoftSqlClient.csproj index 459b175..438cd6b 100644 --- a/src/DeclarativeSql.MicrosoftSqlClient/DeclarativeSql.MicrosoftSqlClient.csproj +++ b/src/DeclarativeSql.MicrosoftSqlClient/DeclarativeSql.MicrosoftSqlClient.csproj @@ -1,7 +1,7 @@  - netstandard2.0;netstandard2.1;net461;net5 + netstandard2.0;netstandard2.1;net461;net5;net6 DeclarativeSql 10.0 enable diff --git a/src/DeclarativeSql.SystemSqlClient/DeclarativeSql.SystemSqlClient.csproj b/src/DeclarativeSql.SystemSqlClient/DeclarativeSql.SystemSqlClient.csproj index 29d94ba..4dff5b6 100644 --- a/src/DeclarativeSql.SystemSqlClient/DeclarativeSql.SystemSqlClient.csproj +++ b/src/DeclarativeSql.SystemSqlClient/DeclarativeSql.SystemSqlClient.csproj @@ -1,7 +1,7 @@  - netstandard2.0;netstandard2.1;net461;net5 + netstandard2.0;netstandard2.1;net461;net5;net6 DeclarativeSql 10.0 enable diff --git a/src/DeclarativeSql.Tests/DeclarativeSql.Tests.csproj b/src/DeclarativeSql.Tests/DeclarativeSql.Tests.csproj index c32a064..e86f27b 100644 --- a/src/DeclarativeSql.Tests/DeclarativeSql.Tests.csproj +++ b/src/DeclarativeSql.Tests/DeclarativeSql.Tests.csproj @@ -1,7 +1,7 @@  - net5 + net6 10.0 enable diff --git a/src/DeclarativeSql/DeclarativeSql.csproj b/src/DeclarativeSql/DeclarativeSql.csproj index db433ed..3711433 100644 --- a/src/DeclarativeSql/DeclarativeSql.csproj +++ b/src/DeclarativeSql/DeclarativeSql.csproj @@ -1,7 +1,7 @@  - netstandard2.0;netstandard2.1;net461;net5 + netstandard2.0;netstandard2.1;net461;net5;net6 10.0 enable true From c8a515fb60675bd4f694780298c71f281d26a19e Mon Sep 17 00:00:00 2001 From: Takaaki Suzuki Date: Wed, 10 Nov 2021 22:24:00 +0900 Subject: [PATCH 03/10] Remove ModuleInitializerAttribute --- .../MicrosoftSqlClientInitializer.cs | 4 +--- .../SystemSqlClientInitializer.cs | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/DeclarativeSql.MicrosoftSqlClient/MicrosoftSqlClientInitializer.cs b/src/DeclarativeSql.MicrosoftSqlClient/MicrosoftSqlClientInitializer.cs index ec38cbe..c90461d 100644 --- a/src/DeclarativeSql.MicrosoftSqlClient/MicrosoftSqlClientInitializer.cs +++ b/src/DeclarativeSql.MicrosoftSqlClient/MicrosoftSqlClientInitializer.cs @@ -1,5 +1,4 @@ -using System.Runtime.CompilerServices; -using DeclarativeSql.DbOperations; +using DeclarativeSql.DbOperations; using Microsoft.Data.SqlClient; @@ -14,7 +13,6 @@ public static class MicrosoftSqlClientInitializer /// /// Initialize. /// - [ModuleInitializer] public static void Initialize() => DbOperation.Factory[typeof(SqlConnection)] = MicrosoftSqlClientOperation.Create; } diff --git a/src/DeclarativeSql.SystemSqlClient/SystemSqlClientInitializer.cs b/src/DeclarativeSql.SystemSqlClient/SystemSqlClientInitializer.cs index 03b8b46..6b362f0 100644 --- a/src/DeclarativeSql.SystemSqlClient/SystemSqlClientInitializer.cs +++ b/src/DeclarativeSql.SystemSqlClient/SystemSqlClientInitializer.cs @@ -1,5 +1,4 @@ using System.Data.SqlClient; -using System.Runtime.CompilerServices; using DeclarativeSql.DbOperations; @@ -14,7 +13,6 @@ public static class SystemSqlClientInitializer /// /// Initialize. /// - [ModuleInitializer] public static void Initialize() => DbOperation.Factory[typeof(SqlConnection)] = SystemSqlClientOperation.Create; } From 075ed51ae3ff3d87479177d9d20fb2e8349e0561 Mon Sep 17 00:00:00 2001 From: Takaaki Suzuki Date: Wed, 10 Nov 2021 22:28:47 +0900 Subject: [PATCH 04/10] Use file-scoped namespace in DeclarativeSql.MicrosoftSqlClient --- .../MicrosoftSqlClientOperation.cs | 241 +++++++++--------- .../Internals/IsExternalInit.cs | 9 +- .../Internals/ModuleInitializerAttribute.cs | 51 ++-- .../MicrosoftSqlClientInitializer.cs | 19 +- 4 files changed, 158 insertions(+), 162 deletions(-) diff --git a/src/DeclarativeSql.MicrosoftSqlClient/DbOperations/MicrosoftSqlClientOperation.cs b/src/DeclarativeSql.MicrosoftSqlClient/DbOperations/MicrosoftSqlClientOperation.cs index 4a7013d..617f3b9 100644 --- a/src/DeclarativeSql.MicrosoftSqlClient/DbOperations/MicrosoftSqlClientOperation.cs +++ b/src/DeclarativeSql.MicrosoftSqlClient/DbOperations/MicrosoftSqlClientOperation.cs @@ -10,140 +10,139 @@ using FastMember; using Microsoft.Data.SqlClient; +namespace DeclarativeSql.DbOperations; -namespace DeclarativeSql.DbOperations + +/// +/// Provides Microsoft.Data.SqlClient specific database operation. +/// +internal class MicrosoftSqlClientOperation : SqlServerOperation { + #region Constructors + /// + /// Creates instance. + /// + /// + /// + /// + /// + private MicrosoftSqlClientOperation(IDbConnection connection, IDbTransaction? transaction, DbProvider provider, int? timeout) + : base(connection, transaction, provider, timeout) + { } + + + /// + /// Creates instance. + /// + /// + /// + /// + /// + public static DbOperation Create(IDbConnection connection, IDbTransaction? transaction, int? timeout) + => new MicrosoftSqlClientOperation(connection, transaction, DbProvider.SqlServer, timeout); + #endregion + + + #region BulkInsert /// - /// Provides Microsoft.Data.SqlClient specific database operation. + /// Inserts the specified data into the table using the bulk method. /// - internal class MicrosoftSqlClientOperation : SqlServerOperation + /// + /// + /// + /// Effected rows count + public override int BulkInsert(IEnumerable data, ValuePriority createdAt) { - #region Constructors - /// - /// Creates instance. - /// - /// - /// - /// - /// - private MicrosoftSqlClientOperation(IDbConnection connection, IDbTransaction? transaction, DbProvider provider, int? timeout) - : base(connection, transaction, provider, timeout) - { } - - - /// - /// Creates instance. - /// - /// - /// - /// - /// - public static DbOperation Create(IDbConnection connection, IDbTransaction? transaction, int? timeout) - => new MicrosoftSqlClientOperation(connection, transaction, DbProvider.SqlServer, timeout); - #endregion - - - #region BulkInsert - /// - /// Inserts the specified data into the table using the bulk method. - /// - /// - /// - /// - /// Effected rows count - public override int BulkInsert(IEnumerable data, ValuePriority createdAt) - { - using var executor = new SqlBulkCopy(this.Connection as SqlConnection, SqlBulkCopyOptions.Default, this.Transaction as SqlTransaction); - data = data.Materialize(); - var param = this.SetupBulkInsert(executor, data, createdAt); - executor.WriteToServer(param); - return data.Count(); - } + using var executor = new SqlBulkCopy(this.Connection as SqlConnection, SqlBulkCopyOptions.Default, this.Transaction as SqlTransaction); + data = data.Materialize(); + var param = this.SetupBulkInsert(executor, data, createdAt); + executor.WriteToServer(param); + return data.Count(); + } - /// - /// Inserts the specified data into the table using the bulk method. - /// - /// - /// - /// - /// - /// Effected rows count - public override async Task BulkInsertAsync(IEnumerable data, ValuePriority createdAt, CancellationToken cancellationToken = default) - { - using var executor = new SqlBulkCopy(this.Connection as SqlConnection, SqlBulkCopyOptions.Default, this.Transaction as SqlTransaction); - data = data.Materialize(); - var param = this.SetupBulkInsert(executor, data, createdAt); - await executor.WriteToServerAsync(param, cancellationToken).ConfigureAwait(false); - return data.Count(); - } + /// + /// Inserts the specified data into the table using the bulk method. + /// + /// + /// + /// + /// + /// Effected rows count + public override async Task BulkInsertAsync(IEnumerable data, ValuePriority createdAt, CancellationToken cancellationToken = default) + { + using var executor = new SqlBulkCopy(this.Connection as SqlConnection, SqlBulkCopyOptions.Default, this.Transaction as SqlTransaction); + data = data.Materialize(); + var param = this.SetupBulkInsert(executor, data, createdAt); + await executor.WriteToServerAsync(param, cancellationToken).ConfigureAwait(false); + return data.Count(); + } - /// - /// Prepares for bulk insertion processing. - /// - /// Mapped type to table. - /// Bulk executor. - /// Inserting target data. - /// - /// Data reader - private DataTable SetupBulkInsert(SqlBulkCopy executor, IEnumerable data, ValuePriority createdAt) - { - //--- Timeout -> CommandTimeout -> BulkCopyTimeout - executor.BulkCopyTimeout = this.Timeout ?? SqlMapper.Settings.CommandTimeout ?? executor.BulkCopyTimeout; - - //--- Target table - var tableMappings = TableInfo.Get(this.DbProvider.Database); - executor.DestinationTableName = tableMappings.FullName; - - //--- Extract mapping columns - var columnMappings - = tableMappings.Columns - .Where(x => !x.IsAutoIncrement) - .Where(x => - { - if (createdAt == ValuePriority.Default) - { - if ((x.IsCreatedAt && x.DefaultValue is not null) - || (x.IsModifiedAt && x.DefaultValue is not null)) - return false; - } - return true; - }) - .ToArray(); - - //--- Setup columns - var columns - = columnMappings - .Select(x => - { - var isNullable = x.MemberType.IsNullable(); - return new DataColumn - { - ColumnName = x.ColumnName, - AllowDBNull = isNullable || x.AllowNull, - DataType = isNullable ? Nullable.GetUnderlyingType(x.MemberType)! : x.MemberType, - }; - }); - var table = new DataTable(); - foreach (var x in columns) + /// + /// Prepares for bulk insertion processing. + /// + /// Mapped type to table. + /// Bulk executor. + /// Inserting target data. + /// + /// Data reader + private DataTable SetupBulkInsert(SqlBulkCopy executor, IEnumerable data, ValuePriority createdAt) + { + //--- Timeout -> CommandTimeout -> BulkCopyTimeout + executor.BulkCopyTimeout = this.Timeout ?? SqlMapper.Settings.CommandTimeout ?? executor.BulkCopyTimeout; + + //--- Target table + var tableMappings = TableInfo.Get(this.DbProvider.Database); + executor.DestinationTableName = tableMappings.FullName; + + //--- Extract mapping columns + var columnMappings + = tableMappings.Columns + .Where(x => !x.IsAutoIncrement) + .Where(x => { - executor.ColumnMappings.Add(x.ColumnName, x.ColumnName); - table.Columns.Add(x); - } + if (createdAt == ValuePriority.Default) + { + if ((x.IsCreatedAt && x.DefaultValue is not null) + || (x.IsModifiedAt && x.DefaultValue is not null)) + return false; + } + return true; + }) + .ToArray(); - //--- Setup rows - foreach (var x in data) + //--- Setup columns + var columns + = columnMappings + .Select(x => { - var row = table.NewRow(); - var accessor = ObjectAccessor.Create(x); - foreach (var y in columnMappings) - row[y.ColumnName] = accessor[y.MemberName] ?? DBNull.Value; - table.Rows.Add(row); - } - return table; + var isNullable = x.MemberType.IsNullable(); + return new DataColumn + { + ColumnName = x.ColumnName, + AllowDBNull = isNullable || x.AllowNull, + DataType = isNullable ? Nullable.GetUnderlyingType(x.MemberType)! : x.MemberType, + }; + }); + var table = new DataTable(); + foreach (var x in columns) + { + executor.ColumnMappings.Add(x.ColumnName, x.ColumnName); + table.Columns.Add(x); + } + + //--- Setup rows + foreach (var x in data) + { + var row = table.NewRow(); + var accessor = ObjectAccessor.Create(x); + foreach (var y in columnMappings) + row[y.ColumnName] = accessor[y.MemberName] ?? DBNull.Value; + table.Rows.Add(row); } - #endregion + return table; } + #endregion } diff --git a/src/DeclarativeSql.MicrosoftSqlClient/Internals/IsExternalInit.cs b/src/DeclarativeSql.MicrosoftSqlClient/Internals/IsExternalInit.cs index e35881c..7b4a6f2 100644 --- a/src/DeclarativeSql.MicrosoftSqlClient/Internals/IsExternalInit.cs +++ b/src/DeclarativeSql.MicrosoftSqlClient/Internals/IsExternalInit.cs @@ -2,9 +2,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace System.Runtime.CompilerServices -{ - internal sealed class IsExternalInit - { } -} +namespace System.Runtime.CompilerServices; + +internal sealed class IsExternalInit +{ } #endif diff --git a/src/DeclarativeSql.MicrosoftSqlClient/Internals/ModuleInitializerAttribute.cs b/src/DeclarativeSql.MicrosoftSqlClient/Internals/ModuleInitializerAttribute.cs index c04fbae..d34b289 100644 --- a/src/DeclarativeSql.MicrosoftSqlClient/Internals/ModuleInitializerAttribute.cs +++ b/src/DeclarativeSql.MicrosoftSqlClient/Internals/ModuleInitializerAttribute.cs @@ -2,30 +2,29 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace System.Runtime.CompilerServices -{ - /// - /// Used to indicate to the compiler that a method should be called - /// in its containing module's initializer. - /// - /// - /// When one or more valid methods - /// with this attribute are found in a compilation, the compiler will - /// emit a module initializer which calls each of the attributed methods. - /// - /// Certain requirements are imposed on any method targeted with this attribute: - /// - The method must be `static`. - /// - The method must be an ordinary member method, as opposed to a property accessor, constructor, local function, etc. - /// - The method must be parameterless. - /// - The method must return `void`. - /// - The method must not be generic or be contained in a generic type. - /// - The method's effective accessibility must be `internal` or `public`. - /// - /// The specification for module initializers in the .NET runtime can be found here: - /// https://github.com/dotnet/runtime/blob/main/docs/design/specs/Ecma-335-Augments.md#module-initializer - /// - [AttributeUsage(AttributeTargets.Method, Inherited = false)] - internal sealed class ModuleInitializerAttribute : Attribute - { } -} +namespace System.Runtime.CompilerServices; + +/// +/// Used to indicate to the compiler that a method should be called +/// in its containing module's initializer. +/// +/// +/// When one or more valid methods +/// with this attribute are found in a compilation, the compiler will +/// emit a module initializer which calls each of the attributed methods. +/// +/// Certain requirements are imposed on any method targeted with this attribute: +/// - The method must be `static`. +/// - The method must be an ordinary member method, as opposed to a property accessor, constructor, local function, etc. +/// - The method must be parameterless. +/// - The method must return `void`. +/// - The method must not be generic or be contained in a generic type. +/// - The method's effective accessibility must be `internal` or `public`. +/// +/// The specification for module initializers in the .NET runtime can be found here: +/// https://github.com/dotnet/runtime/blob/main/docs/design/specs/Ecma-335-Augments.md#module-initializer +/// +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +internal sealed class ModuleInitializerAttribute : Attribute +{ } #endif diff --git a/src/DeclarativeSql.MicrosoftSqlClient/MicrosoftSqlClientInitializer.cs b/src/DeclarativeSql.MicrosoftSqlClient/MicrosoftSqlClientInitializer.cs index c90461d..f129885 100644 --- a/src/DeclarativeSql.MicrosoftSqlClient/MicrosoftSqlClientInitializer.cs +++ b/src/DeclarativeSql.MicrosoftSqlClient/MicrosoftSqlClientInitializer.cs @@ -1,19 +1,18 @@ using DeclarativeSql.DbOperations; using Microsoft.Data.SqlClient; +namespace DeclarativeSql; -namespace DeclarativeSql + +/// +/// Provides initializer to use Microsoft.Data.SqlClient specific feature. +/// +public static class MicrosoftSqlClientInitializer { /// - /// Provides initializer to use Microsoft.Data.SqlClient specific feature. + /// Initialize. /// - public static class MicrosoftSqlClientInitializer - { - /// - /// Initialize. - /// - public static void Initialize() - => DbOperation.Factory[typeof(SqlConnection)] = MicrosoftSqlClientOperation.Create; - } + public static void Initialize() + => DbOperation.Factory[typeof(SqlConnection)] = MicrosoftSqlClientOperation.Create; } From 999b64b80fb8c0f36f310b9fa4b04fe09e495b89 Mon Sep 17 00:00:00 2001 From: Takaaki Suzuki Date: Wed, 10 Nov 2021 22:29:02 +0900 Subject: [PATCH 05/10] Use file-scoped namespace in DeclarativeSql.DeclarativeSql.SystemSqlClient --- .../DbOperations/SystemSqlClientOperation.cs | 241 +++++++++--------- .../Internals/IsExternalInit.cs | 9 +- .../Internals/ModuleInitializerAttribute.cs | 51 ++-- .../SystemSqlClientInitializer.cs | 19 +- 4 files changed, 158 insertions(+), 162 deletions(-) diff --git a/src/DeclarativeSql.SystemSqlClient/DbOperations/SystemSqlClientOperation.cs b/src/DeclarativeSql.SystemSqlClient/DbOperations/SystemSqlClientOperation.cs index 2dc8bb8..12133a2 100644 --- a/src/DeclarativeSql.SystemSqlClient/DbOperations/SystemSqlClientOperation.cs +++ b/src/DeclarativeSql.SystemSqlClient/DbOperations/SystemSqlClientOperation.cs @@ -10,140 +10,139 @@ using DeclarativeSql.Mapping; using FastMember; +namespace DeclarativeSql.DbOperations; -namespace DeclarativeSql.DbOperations + +/// +/// Provides System.Data.SqlClient specific database operation. +/// +internal class SystemSqlClientOperation : SqlServerOperation { + #region Constructors + /// + /// Creates instance. + /// + /// + /// + /// + /// + private SystemSqlClientOperation(IDbConnection connection, IDbTransaction? transaction, DbProvider provider, int? timeout) + : base(connection, transaction, provider, timeout) + { } + + + /// + /// Creates instance. + /// + /// + /// + /// + /// + public static DbOperation Create(IDbConnection connection, IDbTransaction? transaction, int? timeout) + => new SystemSqlClientOperation(connection, transaction, DbProvider.SqlServer, timeout); + #endregion + + + #region BulkInsert /// - /// Provides System.Data.SqlClient specific database operation. + /// Inserts the specified data into the table using the bulk method. /// - internal class SystemSqlClientOperation : SqlServerOperation + /// + /// + /// + /// Effected rows count + public override int BulkInsert(IEnumerable data, ValuePriority createdAt) { - #region Constructors - /// - /// Creates instance. - /// - /// - /// - /// - /// - private SystemSqlClientOperation(IDbConnection connection, IDbTransaction? transaction, DbProvider provider, int? timeout) - : base(connection, transaction, provider, timeout) - { } - - - /// - /// Creates instance. - /// - /// - /// - /// - /// - public static DbOperation Create(IDbConnection connection, IDbTransaction? transaction, int? timeout) - => new SystemSqlClientOperation(connection, transaction, DbProvider.SqlServer, timeout); - #endregion - - - #region BulkInsert - /// - /// Inserts the specified data into the table using the bulk method. - /// - /// - /// - /// - /// Effected rows count - public override int BulkInsert(IEnumerable data, ValuePriority createdAt) - { - using var executor = new SqlBulkCopy(this.Connection as SqlConnection, SqlBulkCopyOptions.Default, this.Transaction as SqlTransaction); - data = data.Materialize(); - var param = this.SetupBulkInsert(executor, data, createdAt); - executor.WriteToServer(param); - return data.Count(); - } + using var executor = new SqlBulkCopy(this.Connection as SqlConnection, SqlBulkCopyOptions.Default, this.Transaction as SqlTransaction); + data = data.Materialize(); + var param = this.SetupBulkInsert(executor, data, createdAt); + executor.WriteToServer(param); + return data.Count(); + } - /// - /// Inserts the specified data into the table using the bulk method. - /// - /// - /// - /// - /// - /// Effected rows count - public override async Task BulkInsertAsync(IEnumerable data, ValuePriority createdAt, CancellationToken cancellationToken = default) - { - using var executor = new SqlBulkCopy(this.Connection as SqlConnection, SqlBulkCopyOptions.Default, this.Transaction as SqlTransaction); - data = data.Materialize(); - var param = this.SetupBulkInsert(executor, data, createdAt); - await executor.WriteToServerAsync(param, cancellationToken).ConfigureAwait(false); - return data.Count(); - } + /// + /// Inserts the specified data into the table using the bulk method. + /// + /// + /// + /// + /// + /// Effected rows count + public override async Task BulkInsertAsync(IEnumerable data, ValuePriority createdAt, CancellationToken cancellationToken = default) + { + using var executor = new SqlBulkCopy(this.Connection as SqlConnection, SqlBulkCopyOptions.Default, this.Transaction as SqlTransaction); + data = data.Materialize(); + var param = this.SetupBulkInsert(executor, data, createdAt); + await executor.WriteToServerAsync(param, cancellationToken).ConfigureAwait(false); + return data.Count(); + } - /// - /// Prepares for bulk insertion processing. - /// - /// Mapped type to table. - /// Bulk executor. - /// Inserting target data. - /// - /// Data reader - private DataTable SetupBulkInsert(SqlBulkCopy executor, IEnumerable data, ValuePriority createdAt) - { - //--- Timeout -> CommandTimeout -> BulkCopyTimeout - executor.BulkCopyTimeout = this.Timeout ?? SqlMapper.Settings.CommandTimeout ?? executor.BulkCopyTimeout; - - //--- Target table - var tableMappings = TableInfo.Get(this.DbProvider.Database); - executor.DestinationTableName = tableMappings.FullName; - - //--- Extract mapping columns - var columnMappings - = tableMappings.Columns - .Where(x => !x.IsAutoIncrement) - .Where(x => - { - if (createdAt == ValuePriority.Default) - { - if ((x.IsCreatedAt && x.DefaultValue is not null) - || (x.IsModifiedAt && x.DefaultValue is not null)) - return false; - } - return true; - }) - .ToArray(); - - //--- Setup columns - var columns - = columnMappings - .Select(x => - { - var isNullable = x.MemberType.IsNullable(); - return new DataColumn - { - ColumnName = x.ColumnName, - AllowDBNull = isNullable || x.AllowNull, - DataType = isNullable ? Nullable.GetUnderlyingType(x.MemberType)! : x.MemberType, - }; - }); - var table = new DataTable(); - foreach (var x in columns) + /// + /// Prepares for bulk insertion processing. + /// + /// Mapped type to table. + /// Bulk executor. + /// Inserting target data. + /// + /// Data reader + private DataTable SetupBulkInsert(SqlBulkCopy executor, IEnumerable data, ValuePriority createdAt) + { + //--- Timeout -> CommandTimeout -> BulkCopyTimeout + executor.BulkCopyTimeout = this.Timeout ?? SqlMapper.Settings.CommandTimeout ?? executor.BulkCopyTimeout; + + //--- Target table + var tableMappings = TableInfo.Get(this.DbProvider.Database); + executor.DestinationTableName = tableMappings.FullName; + + //--- Extract mapping columns + var columnMappings + = tableMappings.Columns + .Where(x => !x.IsAutoIncrement) + .Where(x => { - executor.ColumnMappings.Add(x.ColumnName, x.ColumnName); - table.Columns.Add(x); - } + if (createdAt == ValuePriority.Default) + { + if ((x.IsCreatedAt && x.DefaultValue is not null) + || (x.IsModifiedAt && x.DefaultValue is not null)) + return false; + } + return true; + }) + .ToArray(); - //--- Setup rows - foreach (var x in data) + //--- Setup columns + var columns + = columnMappings + .Select(x => { - var row = table.NewRow(); - var accessor = ObjectAccessor.Create(x); - foreach (var y in columnMappings) - row[y.ColumnName] = accessor[y.MemberName] ?? DBNull.Value; - table.Rows.Add(row); - } - return table; + var isNullable = x.MemberType.IsNullable(); + return new DataColumn + { + ColumnName = x.ColumnName, + AllowDBNull = isNullable || x.AllowNull, + DataType = isNullable ? Nullable.GetUnderlyingType(x.MemberType)! : x.MemberType, + }; + }); + var table = new DataTable(); + foreach (var x in columns) + { + executor.ColumnMappings.Add(x.ColumnName, x.ColumnName); + table.Columns.Add(x); + } + + //--- Setup rows + foreach (var x in data) + { + var row = table.NewRow(); + var accessor = ObjectAccessor.Create(x); + foreach (var y in columnMappings) + row[y.ColumnName] = accessor[y.MemberName] ?? DBNull.Value; + table.Rows.Add(row); } - #endregion + return table; } + #endregion } diff --git a/src/DeclarativeSql.SystemSqlClient/Internals/IsExternalInit.cs b/src/DeclarativeSql.SystemSqlClient/Internals/IsExternalInit.cs index e35881c..7b4a6f2 100644 --- a/src/DeclarativeSql.SystemSqlClient/Internals/IsExternalInit.cs +++ b/src/DeclarativeSql.SystemSqlClient/Internals/IsExternalInit.cs @@ -2,9 +2,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace System.Runtime.CompilerServices -{ - internal sealed class IsExternalInit - { } -} +namespace System.Runtime.CompilerServices; + +internal sealed class IsExternalInit +{ } #endif diff --git a/src/DeclarativeSql.SystemSqlClient/Internals/ModuleInitializerAttribute.cs b/src/DeclarativeSql.SystemSqlClient/Internals/ModuleInitializerAttribute.cs index c04fbae..d34b289 100644 --- a/src/DeclarativeSql.SystemSqlClient/Internals/ModuleInitializerAttribute.cs +++ b/src/DeclarativeSql.SystemSqlClient/Internals/ModuleInitializerAttribute.cs @@ -2,30 +2,29 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace System.Runtime.CompilerServices -{ - /// - /// Used to indicate to the compiler that a method should be called - /// in its containing module's initializer. - /// - /// - /// When one or more valid methods - /// with this attribute are found in a compilation, the compiler will - /// emit a module initializer which calls each of the attributed methods. - /// - /// Certain requirements are imposed on any method targeted with this attribute: - /// - The method must be `static`. - /// - The method must be an ordinary member method, as opposed to a property accessor, constructor, local function, etc. - /// - The method must be parameterless. - /// - The method must return `void`. - /// - The method must not be generic or be contained in a generic type. - /// - The method's effective accessibility must be `internal` or `public`. - /// - /// The specification for module initializers in the .NET runtime can be found here: - /// https://github.com/dotnet/runtime/blob/main/docs/design/specs/Ecma-335-Augments.md#module-initializer - /// - [AttributeUsage(AttributeTargets.Method, Inherited = false)] - internal sealed class ModuleInitializerAttribute : Attribute - { } -} +namespace System.Runtime.CompilerServices; + +/// +/// Used to indicate to the compiler that a method should be called +/// in its containing module's initializer. +/// +/// +/// When one or more valid methods +/// with this attribute are found in a compilation, the compiler will +/// emit a module initializer which calls each of the attributed methods. +/// +/// Certain requirements are imposed on any method targeted with this attribute: +/// - The method must be `static`. +/// - The method must be an ordinary member method, as opposed to a property accessor, constructor, local function, etc. +/// - The method must be parameterless. +/// - The method must return `void`. +/// - The method must not be generic or be contained in a generic type. +/// - The method's effective accessibility must be `internal` or `public`. +/// +/// The specification for module initializers in the .NET runtime can be found here: +/// https://github.com/dotnet/runtime/blob/main/docs/design/specs/Ecma-335-Augments.md#module-initializer +/// +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +internal sealed class ModuleInitializerAttribute : Attribute +{ } #endif diff --git a/src/DeclarativeSql.SystemSqlClient/SystemSqlClientInitializer.cs b/src/DeclarativeSql.SystemSqlClient/SystemSqlClientInitializer.cs index 6b362f0..2d76616 100644 --- a/src/DeclarativeSql.SystemSqlClient/SystemSqlClientInitializer.cs +++ b/src/DeclarativeSql.SystemSqlClient/SystemSqlClientInitializer.cs @@ -1,19 +1,18 @@ using System.Data.SqlClient; using DeclarativeSql.DbOperations; +namespace DeclarativeSql; -namespace DeclarativeSql + +/// +/// Provides initializer to use System.Data.SqlClient specific feature. +/// +public static class SystemSqlClientInitializer { /// - /// Provides initializer to use System.Data.SqlClient specific feature. + /// Initialize. /// - public static class SystemSqlClientInitializer - { - /// - /// Initialize. - /// - public static void Initialize() - => DbOperation.Factory[typeof(SqlConnection)] = SystemSqlClientOperation.Create; - } + public static void Initialize() + => DbOperation.Factory[typeof(SqlConnection)] = SystemSqlClientOperation.Create; } From ee0b19de4fd3bf8de49aa92e4348ae8767a6ea86 Mon Sep 17 00:00:00 2001 From: Takaaki Suzuki Date: Wed, 10 Nov 2021 22:29:27 +0900 Subject: [PATCH 06/10] Use file-scoped namespace in DeclarativeSql.Tests --- src/DeclarativeSql.Tests/Cases/CountTest.cs | 43 +- src/DeclarativeSql.Tests/Cases/DeleteTest.cs | 43 +- src/DeclarativeSql.Tests/Cases/InsertTest.cs | 39 +- .../Cases/MethodChainTest.cs | 219 +++-- src/DeclarativeSql.Tests/Cases/OrderByTest.cs | 39 +- src/DeclarativeSql.Tests/Cases/SelectTest.cs | 139 ++- src/DeclarativeSql.Tests/Cases/ThenByTest.cs | 63 +- .../Cases/TruncateTest.cs | 23 +- src/DeclarativeSql.Tests/Cases/UpdateTest.cs | 99 ++- src/DeclarativeSql.Tests/Cases/WhereTest.cs | 815 +++++++++--------- .../Models/AccessorProvider.cs | 17 +- src/DeclarativeSql.Tests/Models/Person.cs | 37 +- 12 files changed, 783 insertions(+), 793 deletions(-) diff --git a/src/DeclarativeSql.Tests/Cases/CountTest.cs b/src/DeclarativeSql.Tests/Cases/CountTest.cs index bbf06ec..614964d 100644 --- a/src/DeclarativeSql.Tests/Cases/CountTest.cs +++ b/src/DeclarativeSql.Tests/Cases/CountTest.cs @@ -3,37 +3,36 @@ using FluentAssertions; using Xunit; +namespace DeclarativeSql.Tests.Cases; -namespace DeclarativeSql.Tests.Cases + +public class CountTest { - public class CountTest - { - private DbProvider DbProvider { get; } = DbProvider.SqlServer; + private DbProvider DbProvider { get; } = DbProvider.SqlServer; - [Fact] - public void All() - { - var actual = QueryBuilder.Count(this.DbProvider); - var expect = "select count(*) as [Count] from [dbo].[Person]"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); - } + [Fact] + public void All() + { + var actual = QueryBuilder.Count(this.DbProvider); + var expect = "select count(*) as [Count] from [dbo].[Person]"; + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); + } - [Fact] - public void WithCondition() - { - var actual = QueryBuilder.Count(this.DbProvider, x => x.Age >= 30); - var expect = + [Fact] + public void WithCondition() + { + var actual = QueryBuilder.Count(this.DbProvider, x => x.Age >= 30); + var expect = @"select count(*) as [Count] from [dbo].[Person] where [Age] >= @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter!.Count.Should().Be(1); - actual.BindParameter.Should().Contain("p1", 30); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter!.Count.Should().Be(1); + actual.BindParameter.Should().Contain("p1", 30); } } diff --git a/src/DeclarativeSql.Tests/Cases/DeleteTest.cs b/src/DeclarativeSql.Tests/Cases/DeleteTest.cs index dd34ddf..f40da37 100644 --- a/src/DeclarativeSql.Tests/Cases/DeleteTest.cs +++ b/src/DeclarativeSql.Tests/Cases/DeleteTest.cs @@ -3,37 +3,36 @@ using FluentAssertions; using Xunit; +namespace DeclarativeSql.Tests.Cases; -namespace DeclarativeSql.Tests.Cases + +public class DeleteTest { - public class DeleteTest - { - private DbProvider DbProvider { get; } = DbProvider.SqlServer; + private DbProvider DbProvider { get; } = DbProvider.SqlServer; - [Fact] - public void All() - { - var actual = QueryBuilder.Delete(this.DbProvider); - var expect = "delete from [dbo].[Person]"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); - } + [Fact] + public void All() + { + var actual = QueryBuilder.Delete(this.DbProvider); + var expect = "delete from [dbo].[Person]"; + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); + } - [Fact] - public void WithCondition() - { - var actual = QueryBuilder.Delete(this.DbProvider, x => x.Age >= 30); - var expect = + [Fact] + public void WithCondition() + { + var actual = QueryBuilder.Delete(this.DbProvider, x => x.Age >= 30); + var expect = @"delete from [dbo].[Person] where [Age] >= @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter!.Count.Should().Be(1); - actual.BindParameter.Should().Contain("p1", 30); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter!.Count.Should().Be(1); + actual.BindParameter.Should().Contain("p1", 30); } } diff --git a/src/DeclarativeSql.Tests/Cases/InsertTest.cs b/src/DeclarativeSql.Tests/Cases/InsertTest.cs index 3a3860a..a2f0235 100644 --- a/src/DeclarativeSql.Tests/Cases/InsertTest.cs +++ b/src/DeclarativeSql.Tests/Cases/InsertTest.cs @@ -3,20 +3,20 @@ using FluentAssertions; using Xunit; +namespace DeclarativeSql.Tests.Cases; -namespace DeclarativeSql.Tests.Cases + +public class InsertTest { - public class InsertTest - { - private DbProvider DbProvider { get; } = DbProvider.SqlServer; + private DbProvider DbProvider { get; } = DbProvider.SqlServer; - [Fact] - public void CreatedAt_PreferAttribute() - { - var actual = QueryBuilder.Insert(this.DbProvider); - var expect = + [Fact] + public void CreatedAt_PreferAttribute() + { + var actual = QueryBuilder.Insert(this.DbProvider); + var expect = @"insert into [dbo].[Person] ( [名前], @@ -33,16 +33,16 @@ public void CreatedAt_PreferAttribute() SYSDATETIME(), @ModifiedAt )"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); + } - [Fact] - public void CreatedAt_PreferProperty() - { - var actual = QueryBuilder.Insert(this.DbProvider, ValuePriority.Property); - var expect = + [Fact] + public void CreatedAt_PreferProperty() + { + var actual = QueryBuilder.Insert(this.DbProvider, ValuePriority.Property); + var expect = @"insert into [dbo].[Person] ( [名前], @@ -59,8 +59,7 @@ public void CreatedAt_PreferProperty() @CreatedAt, @ModifiedAt )"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); } } diff --git a/src/DeclarativeSql.Tests/Cases/MethodChainTest.cs b/src/DeclarativeSql.Tests/Cases/MethodChainTest.cs index b72b573..e14e751 100644 --- a/src/DeclarativeSql.Tests/Cases/MethodChainTest.cs +++ b/src/DeclarativeSql.Tests/Cases/MethodChainTest.cs @@ -3,44 +3,44 @@ using FluentAssertions; using Xunit; +namespace DeclarativeSql.Tests.Cases; -namespace DeclarativeSql.Tests.Cases + +public class MethodChainTest { - public class MethodChainTest - { - private DbProvider DbProvider { get; } = DbProvider.SqlServer; + private DbProvider DbProvider { get; } = DbProvider.SqlServer; - [Fact] - public void Count_Where() - { - var actual = CreateActualQuery(); - var expect = + [Fact] + public void Count_Where() + { + var actual = CreateActualQuery(); + var expect = @"select count(*) as [Count] from [dbo].[Person] where [Id] = @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", 1); + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", 1); - Query CreateActualQuery() + Query CreateActualQuery() + { + using (var builder = new QueryBuilder(this.DbProvider)) { - using (var builder = new QueryBuilder(this.DbProvider)) - { - builder.Count(); - builder.Where(x => x.Id == 1); - return builder.Build(); - } + builder.Count(); + builder.Where(x => x.Id == 1); + return builder.Build(); } } + } - [Fact] - public void Select_Where() - { - var actual = CreateActualQuery(); - var expect = + [Fact] + public void Select_Where() + { + var actual = CreateActualQuery(); + var expect = @"select [Id] as [Id], [名前] as [Name], @@ -51,27 +51,27 @@ [ModifiedAt] as [ModifiedAt] from [dbo].[Person] where [Id] = @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", 1); + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", 1); - Query CreateActualQuery() + Query CreateActualQuery() + { + using (var builder = new QueryBuilder(this.DbProvider)) { - using (var builder = new QueryBuilder(this.DbProvider)) - { - builder.Select(); - builder.Where(x => x.Id == 1); - return builder.Build(); - } + builder.Select(); + builder.Where(x => x.Id == 1); + return builder.Build(); } } + } - [Fact] - public void Update_Where() - { - var actual = CreateActualQuery(); - var expect = + [Fact] + public void Update_Where() + { + var actual = CreateActualQuery(); + var expect = @"update [dbo].[Person] set [名前] = @Name, @@ -80,51 +80,51 @@ public void Update_Where() [ModifiedAt] = @ModifiedAt where [Id] = @p5"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p5", 1); + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p5", 1); - Query CreateActualQuery() + Query CreateActualQuery() + { + using (var builder = new QueryBuilder(this.DbProvider)) { - using (var builder = new QueryBuilder(this.DbProvider)) - { - builder.Update(); - builder.Where(x => x.Id == 1); - return builder.Build(); - } + builder.Update(); + builder.Where(x => x.Id == 1); + return builder.Build(); } } + } - [Fact] - public void Delete_Where() - { - var actual = CreateActualQuery(); - var expect = + [Fact] + public void Delete_Where() + { + var actual = CreateActualQuery(); + var expect = @"delete from [dbo].[Person] where [Id] = @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", 1); + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", 1); - Query CreateActualQuery() + Query CreateActualQuery() + { + using (var builder = new QueryBuilder(this.DbProvider)) { - using (var builder = new QueryBuilder(this.DbProvider)) - { - builder.Delete(); - builder.Where(x => x.Id == 1); - return builder.Build(); - } + builder.Delete(); + builder.Where(x => x.Id == 1); + return builder.Build(); } } + } - [Fact] - public void Select_OrderBy() - { - var actual = CreateActualQuery(); - var expect = + [Fact] + public void Select_OrderBy() + { + var actual = CreateActualQuery(); + var expect = @"select [Id] as [Id], [名前] as [Name], @@ -135,26 +135,26 @@ [ModifiedAt] as [ModifiedAt] from [dbo].[Person] order by [Id]"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); - Query CreateActualQuery() + Query CreateActualQuery() + { + using (var builder = new QueryBuilder(this.DbProvider)) { - using (var builder = new QueryBuilder(this.DbProvider)) - { - builder.Select(); - builder.OrderBy(x => x.Id); - return builder.Build(); - } + builder.Select(); + builder.OrderBy(x => x.Id); + return builder.Build(); } } + } - [Fact] - public void Select_OrderByDescending() - { - var actual = CreateActualQuery(); - var expect = + [Fact] + public void Select_OrderByDescending() + { + var actual = CreateActualQuery(); + var expect = @"select [Id] as [Id], [名前] as [Name], @@ -165,26 +165,26 @@ [ModifiedAt] as [ModifiedAt] from [dbo].[Person] order by [Id] desc"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); - Query CreateActualQuery() + Query CreateActualQuery() + { + using (var builder = new QueryBuilder(this.DbProvider)) { - using (var builder = new QueryBuilder(this.DbProvider)) - { - builder.Select(); - builder.OrderByDescending(x => x.Id); - return builder.Build(); - } + builder.Select(); + builder.OrderByDescending(x => x.Id); + return builder.Build(); } } + } - [Fact] - public void Select_Where_OrderBy_ThenBy_ThenByDescending() - { - var actual = CreateActualQuery(); - var expect = + [Fact] + public void Select_Where_OrderBy_ThenBy_ThenByDescending() + { + var actual = CreateActualQuery(); + var expect = @"select [Id] as [Id], [名前] as [Name], @@ -199,21 +199,20 @@ order by [Id], [名前], [Age] desc"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", 1); + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", 1); - Query CreateActualQuery() + Query CreateActualQuery() + { + using (var builder = new QueryBuilder(this.DbProvider)) { - using (var builder = new QueryBuilder(this.DbProvider)) - { - builder.Select(); - builder.Where(x => x.Id == 1); - builder.OrderBy(x => x.Id); - builder.ThenBy(x => x.Name); - builder.ThenByDescending(x => x.Age); - return builder.Build(); - } + builder.Select(); + builder.Where(x => x.Id == 1); + builder.OrderBy(x => x.Id); + builder.ThenBy(x => x.Name); + builder.ThenByDescending(x => x.Age); + return builder.Build(); } } } diff --git a/src/DeclarativeSql.Tests/Cases/OrderByTest.cs b/src/DeclarativeSql.Tests/Cases/OrderByTest.cs index 281befa..ac8aa6d 100644 --- a/src/DeclarativeSql.Tests/Cases/OrderByTest.cs +++ b/src/DeclarativeSql.Tests/Cases/OrderByTest.cs @@ -3,36 +3,35 @@ using FluentAssertions; using Xunit; +namespace DeclarativeSql.Tests.Cases; -namespace DeclarativeSql.Tests.Cases + +public class OrderByTest { - public class OrderByTest - { - private DbProvider DbProvider { get; } = DbProvider.SqlServer; + private DbProvider DbProvider { get; } = DbProvider.SqlServer; - [Fact] - public void Ascending() - { - var actual = QueryBuilder.OrderBy(this.DbProvider, x => x.Name); - var expect = + [Fact] + public void Ascending() + { + var actual = QueryBuilder.OrderBy(this.DbProvider, x => x.Name); + var expect = @"order by [名前]"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); + } - [Fact] - public void Descending() - { - var actual = QueryBuilder.OrderByDescending(this.DbProvider, x => x.Age); - var expect = + [Fact] + public void Descending() + { + var actual = QueryBuilder.OrderByDescending(this.DbProvider, x => x.Age); + var expect = @"order by [Age] desc"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); } } diff --git a/src/DeclarativeSql.Tests/Cases/SelectTest.cs b/src/DeclarativeSql.Tests/Cases/SelectTest.cs index 2b9546f..77bf158 100644 --- a/src/DeclarativeSql.Tests/Cases/SelectTest.cs +++ b/src/DeclarativeSql.Tests/Cases/SelectTest.cs @@ -3,20 +3,20 @@ using FluentAssertions; using Xunit; +namespace DeclarativeSql.Tests.Cases; -namespace DeclarativeSql.Tests.Cases + +public class SelectTest { - public class SelectTest - { - private DbProvider DbProvider { get; } = DbProvider.SqlServer; + private DbProvider DbProvider { get; } = DbProvider.SqlServer; - [Fact] - public void AllColumns() - { - var actual = QueryBuilder.Select(this.DbProvider); - var expect = + [Fact] + public void AllColumns() + { + var actual = QueryBuilder.Select(this.DbProvider); + var expect = @"select [Id] as [Id], [名前] as [Name], @@ -25,106 +25,105 @@ public void AllColumns() [CreatedAt] as [CreatedAt], [ModifiedAt] as [ModifiedAt] from [dbo].[Person]"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); + } - [Fact] - public void OneColumn() - { - var actual = QueryBuilder.Select(this.DbProvider, x => x.Name); - var expect = + [Fact] + public void OneColumn() + { + var actual = QueryBuilder.Select(this.DbProvider, x => x.Name); + var expect = @"select [名前] as [Name] from [dbo].[Person]"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); + } - [Fact] - public void OneColumn_AnonymousType() - { - var actual = QueryBuilder.Select(this.DbProvider, x => new { x.Name }); - var expect = + [Fact] + public void OneColumn_AnonymousType() + { + var actual = QueryBuilder.Select(this.DbProvider, x => new { x.Name }); + var expect = @"select [名前] as [Name] from [dbo].[Person]"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); + } - [Fact] - public void TwoColumns() - { - var actual = QueryBuilder.Select(this.DbProvider, x => new { x.Name, x.Age }); - var expect = + [Fact] + public void TwoColumns() + { + var actual = QueryBuilder.Select(this.DbProvider, x => new { x.Name, x.Age }); + var expect = @"select [名前] as [Name], [Age] as [Age] from [dbo].[Person]"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); + } - [Fact] - public void OneColumn_Cast() - { - var actual = QueryBuilder.Select(this.DbProvider, x => (object)x.Name); - var expect = + [Fact] + public void OneColumn_Cast() + { + var actual = QueryBuilder.Select(this.DbProvider, x => (object)x.Name); + var expect = @"select [名前] as [Name] from [dbo].[Person]"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); + } - [Fact] - public void OneColumn_AnonymousType_Cast() - { - var actual = QueryBuilder.Select(this.DbProvider, x => (object)new { x.Name }); - var expect = + [Fact] + public void OneColumn_AnonymousType_Cast() + { + var actual = QueryBuilder.Select(this.DbProvider, x => (object)new { x.Name }); + var expect = @"select [名前] as [Name] from [dbo].[Person]"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); + } - [Fact] - public void TwoColumns_Cast() - { - var actual = QueryBuilder.Select(this.DbProvider, x => (object)new { x.Name, x.Age }); - var expect = + [Fact] + public void TwoColumns_Cast() + { + var actual = QueryBuilder.Select(this.DbProvider, x => (object)new { x.Name, x.Age }); + var expect = @"select [名前] as [Name], [Age] as [Age] from [dbo].[Person]"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); + } - [Fact] - public void WithCondition() - { - var actual = QueryBuilder.Select(this.DbProvider, x => x.Age >= 30, x => new { x.Name, x.Age }); - var expect = + [Fact] + public void WithCondition() + { + var actual = QueryBuilder.Select(this.DbProvider, x => x.Age >= 30, x => new { x.Name, x.Age }); + var expect = @"select [名前] as [Name], [Age] as [Age] from [dbo].[Person] where [Age] >= @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter!.Count.Should().Be(1); - actual.BindParameter.Should().Contain("p1", 30); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter!.Count.Should().Be(1); + actual.BindParameter.Should().Contain("p1", 30); } } diff --git a/src/DeclarativeSql.Tests/Cases/ThenByTest.cs b/src/DeclarativeSql.Tests/Cases/ThenByTest.cs index b8b183c..166e7a2 100644 --- a/src/DeclarativeSql.Tests/Cases/ThenByTest.cs +++ b/src/DeclarativeSql.Tests/Cases/ThenByTest.cs @@ -3,57 +3,56 @@ using FluentAssertions; using Xunit; +namespace DeclarativeSql.Tests.Cases; -namespace DeclarativeSql.Tests.Cases + +public class ThenByTest { - public class ThenByTest - { - private DbProvider DbProvider { get; } = DbProvider.SqlServer; + private DbProvider DbProvider { get; } = DbProvider.SqlServer; - [Fact] - public void Ascending() - { - var actual = CreateActualQuery(); - var expect = + [Fact] + public void Ascending() + { + var actual = CreateActualQuery(); + var expect = @"order by [名前], [CreatedAt]"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); - Query CreateActualQuery() + Query CreateActualQuery() + { + using (var builder = new QueryBuilder(this.DbProvider)) { - using (var builder = new QueryBuilder(this.DbProvider)) - { - builder.OrderBy(x => x.Name); - builder.ThenBy(x => x.CreatedAt); - return builder.Build(); - } + builder.OrderBy(x => x.Name); + builder.ThenBy(x => x.CreatedAt); + return builder.Build(); } } + } - [Fact] - public void Descending() - { - var actual = CreateActualQuery(); - var expect = + [Fact] + public void Descending() + { + var actual = CreateActualQuery(); + var expect = @"order by [Age] desc, [ModifiedAt] desc"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); - Query CreateActualQuery() + Query CreateActualQuery() + { + using (var builder = new QueryBuilder(this.DbProvider)) { - using (var builder = new QueryBuilder(this.DbProvider)) - { - builder.OrderByDescending(x => x.Age); - builder.ThenByDescending(x => x.ModifiedAt); - return builder.Build(); - } + builder.OrderByDescending(x => x.Age); + builder.ThenByDescending(x => x.ModifiedAt); + return builder.Build(); } } } diff --git a/src/DeclarativeSql.Tests/Cases/TruncateTest.cs b/src/DeclarativeSql.Tests/Cases/TruncateTest.cs index a8bc2ee..23f65d4 100644 --- a/src/DeclarativeSql.Tests/Cases/TruncateTest.cs +++ b/src/DeclarativeSql.Tests/Cases/TruncateTest.cs @@ -3,22 +3,21 @@ using FluentAssertions; using Xunit; +namespace DeclarativeSql.Tests.Cases; -namespace DeclarativeSql.Tests.Cases + +public class TruncateTest { - public class TruncateTest - { - private DbProvider DbProvider { get; } = DbProvider.SqlServer; + private DbProvider DbProvider { get; } = DbProvider.SqlServer; - [Fact] - public void Create() - { - var actual = QueryBuilder.Truncate(this.DbProvider); - var expect = "truncate table [dbo].[Person]"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); - } + [Fact] + public void Create() + { + var actual = QueryBuilder.Truncate(this.DbProvider); + var expect = "truncate table [dbo].[Person]"; + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); } } diff --git a/src/DeclarativeSql.Tests/Cases/UpdateTest.cs b/src/DeclarativeSql.Tests/Cases/UpdateTest.cs index 4b030f4..1bce02e 100644 --- a/src/DeclarativeSql.Tests/Cases/UpdateTest.cs +++ b/src/DeclarativeSql.Tests/Cases/UpdateTest.cs @@ -3,92 +3,91 @@ using FluentAssertions; using Xunit; +namespace DeclarativeSql.Tests.Cases; -namespace DeclarativeSql.Tests.Cases + +public class UpdateTest { - public class UpdateTest - { - private DbProvider DbProvider { get; } = DbProvider.SqlServer; + private DbProvider DbProvider { get; } = DbProvider.SqlServer; - [Fact] - public void AllColumns() - { - var actual = QueryBuilder.Update(this.DbProvider); - var expect = + [Fact] + public void AllColumns() + { + var actual = QueryBuilder.Update(this.DbProvider); + var expect = @"update [dbo].[Person] set [名前] = @Name, [Age] = @Age, [HasChildren] = @HasChildren, [ModifiedAt] = @ModifiedAt"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter!.Count.Should().Be(4); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter!.Count.Should().Be(4); + } - [Fact] - public void OneColumn() - { - var actual = QueryBuilder.Update(this.DbProvider, x => x.Name); - var expect = + [Fact] + public void OneColumn() + { + var actual = QueryBuilder.Update(this.DbProvider, x => x.Name); + var expect = @"update [dbo].[Person] set [名前] = @Name, [ModifiedAt] = @ModifiedAt"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter!.Count.Should().Be(2); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter!.Count.Should().Be(2); + } - [Fact] - public void OneColumn_AnonymousType() - { - var actual = QueryBuilder.Update(this.DbProvider, x => new { x.Name }); - var expect = + [Fact] + public void OneColumn_AnonymousType() + { + var actual = QueryBuilder.Update(this.DbProvider, x => new { x.Name }); + var expect = @"update [dbo].[Person] set [名前] = @Name, [ModifiedAt] = @ModifiedAt"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter!.Count.Should().Be(2); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter!.Count.Should().Be(2); + } - [Fact] - public void TwoColumns() - { - var actual = QueryBuilder.Update(this.DbProvider, x => new { x.Name, x.CreatedAt }); - var expect = + [Fact] + public void TwoColumns() + { + var actual = QueryBuilder.Update(this.DbProvider, x => new { x.Name, x.CreatedAt }); + var expect = @"update [dbo].[Person] set [名前] = @Name, [ModifiedAt] = @ModifiedAt"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter!.Count.Should().Be(2); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter!.Count.Should().Be(2); + } - [Fact] - public void TwoColumns_WithCondition() - { - var actual = QueryBuilder.Update(this.DbProvider, x => x.Age >= 30, x => new { x.Name, x.CreatedAt }); - var expect = + [Fact] + public void TwoColumns_WithCondition() + { + var actual = QueryBuilder.Update(this.DbProvider, x => x.Age >= 30, x => new { x.Name, x.CreatedAt }); + var expect = @"update [dbo].[Person] set [名前] = @Name, [ModifiedAt] = @ModifiedAt where [Age] >= @p3"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter!.Count.Should().Be(3); - actual.BindParameter.Should().Contain("p3", 30); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter!.Count.Should().Be(3); + actual.BindParameter.Should().Contain("p3", 30); } } diff --git a/src/DeclarativeSql.Tests/Cases/WhereTest.cs b/src/DeclarativeSql.Tests/Cases/WhereTest.cs index 41b4bac..6ade6be 100644 --- a/src/DeclarativeSql.Tests/Cases/WhereTest.cs +++ b/src/DeclarativeSql.Tests/Cases/WhereTest.cs @@ -5,508 +5,507 @@ using FluentAssertions; using Xunit; +namespace DeclarativeSql.Tests.Cases; -namespace DeclarativeSql.Tests.Cases + +public class WhereTest { - public class WhereTest - { - private DbProvider DbProvider { get; } = DbProvider.SqlServer; + private DbProvider DbProvider { get; } = DbProvider.SqlServer; - [Fact] - public void Equal() - { - var actual = QueryBuilder.Where(this.DbProvider, x => x.Id == 1); - var expect = + [Fact] + public void Equal() + { + var actual = QueryBuilder.Where(this.DbProvider, x => x.Id == 1); + var expect = @"where [Id] = @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", 1); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", 1); + } - [Fact] - public void NotEqual() - { - var actual = QueryBuilder.Where(this.DbProvider, x => x.Id != 1); - var expect = + [Fact] + public void NotEqual() + { + var actual = QueryBuilder.Where(this.DbProvider, x => x.Id != 1); + var expect = @"where [Id] <> @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", 1); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", 1); + } - [Fact] - public void GreaterThan() - { - var actual = QueryBuilder.Where(this.DbProvider, x => x.Id > 1); - var expect = + [Fact] + public void GreaterThan() + { + var actual = QueryBuilder.Where(this.DbProvider, x => x.Id > 1); + var expect = @"where [Id] > @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", 1); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", 1); + } - [Fact] - public void LessThan() - { - var actual = QueryBuilder.Where(this.DbProvider, x => x.Id < 1); - var expect = + [Fact] + public void LessThan() + { + var actual = QueryBuilder.Where(this.DbProvider, x => x.Id < 1); + var expect = @"where [Id] < @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", 1); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", 1); + } - [Fact] - public void GreaterThanOrEqual() - { - var actual = QueryBuilder.Where(this.DbProvider, x => x.Id >= 1); - var expect = + [Fact] + public void GreaterThanOrEqual() + { + var actual = QueryBuilder.Where(this.DbProvider, x => x.Id >= 1); + var expect = @"where [Id] >= @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", 1); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", 1); + } - [Fact] - public void LessThanOrEqual() - { - var actual = QueryBuilder.Where(this.DbProvider, x => x.Id <= 1); - var expect = + [Fact] + public void LessThanOrEqual() + { + var actual = QueryBuilder.Where(this.DbProvider, x => x.Id <= 1); + var expect = @"where [Id] <= @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", 1); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", 1); + } - [Fact] - public void Null() - { - var actual = QueryBuilder.Where(this.DbProvider, x => x.Name == null); - var expect = + [Fact] + public void Null() + { + var actual = QueryBuilder.Where(this.DbProvider, x => x.Name == null); + var expect = @"where [名前] is null"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); + } - [Fact] - public void NotNull() - { - var actual = QueryBuilder.Where(this.DbProvider, x => x.Name != null); - var expect = + [Fact] + public void NotNull() + { + var actual = QueryBuilder.Where(this.DbProvider, x => x.Name != null); + var expect = @"where [名前] is not null"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); + } - [Fact] - public void And() - { - var actual = QueryBuilder.Where(this.DbProvider, x => x.Id > 1 && x.Name == "xin9le"); - var expect = + [Fact] + public void And() + { + var actual = QueryBuilder.Where(this.DbProvider, x => x.Id > 1 && x.Name == "xin9le"); + var expect = @"where [Id] > @p1 and [名前] = @p2"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", 1); - actual.BindParameter.Should().Contain("p2", "xin9le"); - } - - - [Fact] - public void Or() - { - var actual = QueryBuilder.Where(this.DbProvider, x => x.Id > 1 || x.Name == "xin9le"); - var expect = + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", 1); + actual.BindParameter.Should().Contain("p2", "xin9le"); + } + + + [Fact] + public void Or() + { + var actual = QueryBuilder.Where(this.DbProvider, x => x.Id > 1 || x.Name == "xin9le"); + var expect = @"where [Id] > @p1 or [名前] = @p2"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", 1); - actual.BindParameter.Should().Contain("p2", "xin9le"); - } - - - [Fact] - public void AndOr1() - { - var actual = QueryBuilder.Where(this.DbProvider, x => x.Id > 1 && x.Name == "xin9le" || x.Age <= 30); - var expect = + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", 1); + actual.BindParameter.Should().Contain("p2", "xin9le"); + } + + + [Fact] + public void AndOr1() + { + var actual = QueryBuilder.Where(this.DbProvider, x => x.Id > 1 && x.Name == "xin9le" || x.Age <= 30); + var expect = @"where ([Id] > @p1 and [名前] = @p2) or [Age] <= @p3"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", 1); - actual.BindParameter.Should().Contain("p2", "xin9le"); - actual.BindParameter.Should().Contain("p3", 30); - } - - - [Fact] - public void AndOr2() - { - var actual = QueryBuilder.Where(this.DbProvider, x => x.Id > 1 && (x.Name == "xin9le" || x.Age <= 30)); - var expect = + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", 1); + actual.BindParameter.Should().Contain("p2", "xin9le"); + actual.BindParameter.Should().Contain("p3", 30); + } + + + [Fact] + public void AndOr2() + { + var actual = QueryBuilder.Where(this.DbProvider, x => x.Id > 1 && (x.Name == "xin9le" || x.Age <= 30)); + var expect = @"where [Id] > @p1 and ([名前] = @p2 or [Age] <= @p3)"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", 1); - actual.BindParameter.Should().Contain("p2", "xin9le"); - actual.BindParameter.Should().Contain("p3", 30); - } - - - [Fact] - public void AndOr3() - { - var actual = QueryBuilder.Where(this.DbProvider, x => x.Id > 1 || x.Name == "xin9le" && x.Age <= 30); - var expect = + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", 1); + actual.BindParameter.Should().Contain("p2", "xin9le"); + actual.BindParameter.Should().Contain("p3", 30); + } + + + [Fact] + public void AndOr3() + { + var actual = QueryBuilder.Where(this.DbProvider, x => x.Id > 1 || x.Name == "xin9le" && x.Age <= 30); + var expect = @"where [Id] > @p1 or ([名前] = @p2 and [Age] <= @p3)"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", 1); - actual.BindParameter.Should().Contain("p2", "xin9le"); - actual.BindParameter.Should().Contain("p3", 30); - } - - - [Fact] - public void AndOr4() - { - var actual = QueryBuilder.Where(this.DbProvider, x => (x.Id > 1 || x.Name == "xin9le") && x.Age <= 30); - var expect = + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", 1); + actual.BindParameter.Should().Contain("p2", "xin9le"); + actual.BindParameter.Should().Contain("p3", 30); + } + + + [Fact] + public void AndOr4() + { + var actual = QueryBuilder.Where(this.DbProvider, x => (x.Id > 1 || x.Name == "xin9le") && x.Age <= 30); + var expect = @"where ([Id] > @p1 or [名前] = @p2) and [Age] <= @p3"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", 1); - actual.BindParameter.Should().Contain("p2", "xin9le"); - actual.BindParameter.Should().Contain("p3", 30); - } - - - [Fact] - public void AndOr5() - { - var value1 = Enumerable.Range(0, 1000).ToArray(); - var value2 = Enumerable.Range(1000, 234).ToArray(); - var value = value1.Concat(value2); - var actual = QueryBuilder.Where(this.DbProvider, x => (x.Id > 1 || x.Name == "xin9le") && x.Age <= 30 && value.Contains(x.Id)); - var expect = + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", 1); + actual.BindParameter.Should().Contain("p2", "xin9le"); + actual.BindParameter.Should().Contain("p3", 30); + } + + + [Fact] + public void AndOr5() + { + var value1 = Enumerable.Range(0, 1000).ToArray(); + var value2 = Enumerable.Range(1000, 234).ToArray(); + var value = value1.Concat(value2); + var actual = QueryBuilder.Where(this.DbProvider, x => (x.Id > 1 || x.Name == "xin9le") && x.Age <= 30 && value.Contains(x.Id)); + var expect = @"where ([Id] > @p1 or [名前] = @p2) and [Age] <= @p3 and ([Id] in @p4 or [Id] in @p5)"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", 1); - actual.BindParameter.Should().Contain("p2", "xin9le"); - actual.BindParameter.Should().Contain("p3", 30); - actual.BindParameter.Should().ContainKey("p4"); - actual.BindParameter!["p4"].Should().BeEquivalentTo(value1); - actual.BindParameter.Should().ContainKey("p5"); - actual.BindParameter!["p5"].Should().BeEquivalentTo(value2); - - } - - - [Fact] - public void AndOr6() - { - var value1 = Enumerable.Range(0, 1000).ToArray(); - var value2 = Enumerable.Range(1000, 234).ToArray(); - var value = value1.Concat(value2); - var actual = QueryBuilder.Where(this.DbProvider, x => (x.Id > 1 || x.Name == "xin9le") && x.Age <= 30 || value.Contains(x.Id)); - var expect = + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", 1); + actual.BindParameter.Should().Contain("p2", "xin9le"); + actual.BindParameter.Should().Contain("p3", 30); + actual.BindParameter.Should().ContainKey("p4"); + actual.BindParameter!["p4"].Should().BeEquivalentTo(value1); + actual.BindParameter.Should().ContainKey("p5"); + actual.BindParameter!["p5"].Should().BeEquivalentTo(value2); + + } + + + [Fact] + public void AndOr6() + { + var value1 = Enumerable.Range(0, 1000).ToArray(); + var value2 = Enumerable.Range(1000, 234).ToArray(); + var value = value1.Concat(value2); + var actual = QueryBuilder.Where(this.DbProvider, x => (x.Id > 1 || x.Name == "xin9le") && x.Age <= 30 || value.Contains(x.Id)); + var expect = @"where (([Id] > @p1 or [名前] = @p2) and [Age] <= @p3) or ([Id] in @p4 or [Id] in @p5)"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", 1); - actual.BindParameter.Should().Contain("p2", "xin9le"); - actual.BindParameter.Should().Contain("p3", 30); - actual.BindParameter.Should().ContainKey("p4"); - actual.BindParameter!["p4"].Should().BeEquivalentTo(value1); - actual.BindParameter.Should().ContainKey("p5"); - actual.BindParameter!["p5"].Should().BeEquivalentTo(value2); - } - - - [Fact] - public void AndOr7() - { - var values = System.Array.Empty(); - var actual = QueryBuilder.Where(this.DbProvider, x => (x.Id > 1 || x.Name == "xin9le") && x.Age <= 30 || values.Contains(x.Id)); - var expect = + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", 1); + actual.BindParameter.Should().Contain("p2", "xin9le"); + actual.BindParameter.Should().Contain("p3", 30); + actual.BindParameter.Should().ContainKey("p4"); + actual.BindParameter!["p4"].Should().BeEquivalentTo(value1); + actual.BindParameter.Should().ContainKey("p5"); + actual.BindParameter!["p5"].Should().BeEquivalentTo(value2); + } + + + [Fact] + public void AndOr7() + { + var values = System.Array.Empty(); + var actual = QueryBuilder.Where(this.DbProvider, x => (x.Id > 1 || x.Name == "xin9le") && x.Age <= 30 || values.Contains(x.Id)); + var expect = @"where (([Id] > @p1 or [名前] = @p2) and [Age] <= @p3) or 1 = 0"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", 1); - actual.BindParameter.Should().Contain("p2", "xin9le"); - actual.BindParameter.Should().Contain("p3", 30); - } - - - [Fact] - public void AndOr8() - { - var values = System.Array.Empty(); - var actual = QueryBuilder.Where(this.DbProvider, x => (x.Id > 1 || x.Name == "xin9le") && (x.Age <= 30 || values.Contains(x.Id))); - var expect = + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", 1); + actual.BindParameter.Should().Contain("p2", "xin9le"); + actual.BindParameter.Should().Contain("p3", 30); + } + + + [Fact] + public void AndOr8() + { + var values = System.Array.Empty(); + var actual = QueryBuilder.Where(this.DbProvider, x => (x.Id > 1 || x.Name == "xin9le") && (x.Age <= 30 || values.Contains(x.Id))); + var expect = @"where ([Id] > @p1 or [名前] = @p2) and ([Age] <= @p3 or 1 = 0)"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", 1); - actual.BindParameter.Should().Contain("p2", "xin9le"); - actual.BindParameter.Should().Contain("p3", 30); - } - - - [Fact] - public void Contains_IEnumerable() - { - var value = Enumerable.Range(0, 3).ToArray(); - var actual = QueryBuilder.Where(this.DbProvider, x => value.Contains(x.Id)); - var expect = + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", 1); + actual.BindParameter.Should().Contain("p2", "xin9le"); + actual.BindParameter.Should().Contain("p3", 30); + } + + + [Fact] + public void Contains_IEnumerable() + { + var value = Enumerable.Range(0, 3).ToArray(); + var actual = QueryBuilder.Where(this.DbProvider, x => value.Contains(x.Id)); + var expect = @"where [Id] in @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().ContainKey("p1"); - actual.BindParameter!["p1"].Should().BeEquivalentTo(value); - } - - - [Fact] - public void Contains_IEnumerable_Over1000() - { - var value1 = Enumerable.Range(0, 1000).ToArray(); - var value2 = Enumerable.Range(1000, 234).ToArray(); - var value = value1.Concat(value2); - var actual = QueryBuilder.Where(this.DbProvider, x => value.Contains(x.Id)); - var expect = + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().ContainKey("p1"); + actual.BindParameter!["p1"].Should().BeEquivalentTo(value); + } + + + [Fact] + public void Contains_IEnumerable_Over1000() + { + var value1 = Enumerable.Range(0, 1000).ToArray(); + var value2 = Enumerable.Range(1000, 234).ToArray(); + var value = value1.Concat(value2); + var actual = QueryBuilder.Where(this.DbProvider, x => value.Contains(x.Id)); + var expect = @"where ([Id] in @p1 or [Id] in @p2)"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().ContainKey("p1"); - actual.BindParameter!["p1"].Should().BeEquivalentTo(value1); - actual.BindParameter.Should().ContainKey("p2"); - actual.BindParameter!["p2"].Should().BeEquivalentTo(value2); - } - - - [Fact] - public void Contains_IEnumerable_NoElements() - { - var values = System.Array.Empty(); - var actual = QueryBuilder.Where(this.DbProvider, x => values.Contains(x.Id)); - var expect = + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().ContainKey("p1"); + actual.BindParameter!["p1"].Should().BeEquivalentTo(value1); + actual.BindParameter.Should().ContainKey("p2"); + actual.BindParameter!["p2"].Should().BeEquivalentTo(value2); + } + + + [Fact] + public void Contains_IEnumerable_NoElements() + { + var values = System.Array.Empty(); + var actual = QueryBuilder.Where(this.DbProvider, x => values.Contains(x.Id)); + var expect = @"where 1 = 0"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().BeNull(); - } - - - [Fact] - public void Contains_ConcreteType() - { - var value1 = Enumerable.Range(0, 1000).ToArray(); - var value2 = Enumerable.Range(1000, 234).ToArray(); - var value = value1.Concat(value2).ToHashSet(); - var actual = QueryBuilder.Where(this.DbProvider, x => value.Contains(x.Id)); - var expect = + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().BeNull(); + } + + + [Fact] + public void Contains_ConcreteType() + { + var value1 = Enumerable.Range(0, 1000).ToArray(); + var value2 = Enumerable.Range(1000, 234).ToArray(); + var value = value1.Concat(value2).ToHashSet(); + var actual = QueryBuilder.Where(this.DbProvider, x => value.Contains(x.Id)); + var expect = @"where ([Id] in @p1 or [Id] in @p2)"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().ContainKey("p1"); - actual.BindParameter!["p1"].Should().BeEquivalentTo(value1); - actual.BindParameter.Should().ContainKey("p2"); - actual.BindParameter!["p2"].Should().BeEquivalentTo(value2); - } - - - [Fact] - public void Variable() - { - var id = 1; - var actual = QueryBuilder.Where(this.DbProvider, x => x.Id == id); - var expect = + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().ContainKey("p1"); + actual.BindParameter!["p1"].Should().BeEquivalentTo(value1); + actual.BindParameter.Should().ContainKey("p2"); + actual.BindParameter!["p2"].Should().BeEquivalentTo(value2); + } + + + [Fact] + public void Variable() + { + var id = 1; + var actual = QueryBuilder.Where(this.DbProvider, x => x.Id == id); + var expect = @"where [Id] = @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", id); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", id); + } - [Fact] - public void Constructor() - { - var actual = QueryBuilder.Where(this.DbProvider, x => x.Name == new string('a', 3)); - var expect = + [Fact] + public void Constructor() + { + var actual = QueryBuilder.Where(this.DbProvider, x => x.Name == new string('a', 3)); + var expect = @"where [名前] = @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", "aaa"); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", "aaa"); + } - [Fact] - public void Array() - { - // do nothing - } + [Fact] + public void Array() + { + // do nothing + } - [Fact] - public void InstanceMethod() - { - var some = new AccessorProvider(); - var actual = QueryBuilder.Where(this.DbProvider, x => x.Name == some.InstanceMethod()); - var expect = + [Fact] + public void InstanceMethod() + { + var some = new AccessorProvider(); + var actual = QueryBuilder.Where(this.DbProvider, x => x.Name == some.InstanceMethod()); + var expect = @"where [名前] = @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", some.InstanceMethod()); - } - - - [Fact] - public void Lambda() - { - Func getName = x => x.ToString(); - var actual = QueryBuilder.Where(this.DbProvider, x => x.Name == getName(123)); - var expect = + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", some.InstanceMethod()); + } + + + [Fact] + public void Lambda() + { + Func getName = x => x.ToString(); + var actual = QueryBuilder.Where(this.DbProvider, x => x.Name == getName(123)); + var expect = @"where [名前] = @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", "123"); - } - - - [Fact] - public void InstanceProperty() - { - var some = new AccessorProvider(); - var actual = QueryBuilder.Where(this.DbProvider, x => x.Age == some.InstanceProperty); - var expect = + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", "123"); + } + + + [Fact] + public void InstanceProperty() + { + var some = new AccessorProvider(); + var actual = QueryBuilder.Where(this.DbProvider, x => x.Age == some.InstanceProperty); + var expect = @"where [Age] = @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", some.InstanceProperty); - } - - - [Fact] - public void Indexer() - { - var ids = new[] { 1, 2, 3 }; - var actual = QueryBuilder.Where(this.DbProvider, x => x.Id == ids[0]); - var expect = + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", some.InstanceProperty); + } + + + [Fact] + public void Indexer() + { + var ids = new[] { 1, 2, 3 }; + var actual = QueryBuilder.Where(this.DbProvider, x => x.Id == ids[0]); + var expect = @"where [Id] = @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", ids[0]); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", ids[0]); + } - [Fact] - public void StaticMethod() - { - var actual = QueryBuilder.Where(this.DbProvider, x => x.Name == AccessorProvider.StaticMethod()); - var expect = + [Fact] + public void StaticMethod() + { + var actual = QueryBuilder.Where(this.DbProvider, x => x.Name == AccessorProvider.StaticMethod()); + var expect = @"where [名前] = @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", AccessorProvider.StaticMethod()); - } + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", AccessorProvider.StaticMethod()); + } - [Fact] - public void StaticProperty() - { - var actual = QueryBuilder.Where(this.DbProvider, x => x.Age == AccessorProvider.StaticProperty); - var expect = + [Fact] + public void StaticProperty() + { + var actual = QueryBuilder.Where(this.DbProvider, x => x.Age == AccessorProvider.StaticProperty); + var expect = @"where [Age] = @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", AccessorProvider.StaticProperty); - } - -/* - [Fact] - public void Boolean() - { - var actual = QueryBuilder.Where(this.DbProvider, x => x.HasChildren); - var expect = -@"where - [HasChildren] = @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", true); - } - - - [Fact] - public void InverseBoolean() - { - var actual = QueryBuilder.Where(this.DbProvider, x => !x.HasChildren); - var expect = -@"where - [HasChildren] <> @p1"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", true); - } - - - [Fact] - public void BooleanAndOr() - { - var actual = QueryBuilder.Where(this.DbProvider, x => x.HasChildren == true || x.Id != 0 || x.Name == "xin9le" && !x.HasChildren); - var expect = -@"where - [HasChildren] = @p1 or [Id] <> @p2 or ([名前] = @p3 and [HasChildren] <> @p4)"; - actual.Statement.Should().Be(expect); - actual.BindParameter.Should().NotBeNull(); - actual.BindParameter.Should().Contain("p1", true); - actual.BindParameter.Should().Contain("p2", 0); - actual.BindParameter.Should().Contain("p3", "xin9le"); - actual.BindParameter.Should().Contain("p4", true); - } -*/ + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", AccessorProvider.StaticProperty); } + + /* + [Fact] + public void Boolean() + { + var actual = QueryBuilder.Where(this.DbProvider, x => x.HasChildren); + var expect = + @"where + [HasChildren] = @p1"; + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", true); + } + + + [Fact] + public void InverseBoolean() + { + var actual = QueryBuilder.Where(this.DbProvider, x => !x.HasChildren); + var expect = + @"where + [HasChildren] <> @p1"; + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", true); + } + + + [Fact] + public void BooleanAndOr() + { + var actual = QueryBuilder.Where(this.DbProvider, x => x.HasChildren == true || x.Id != 0 || x.Name == "xin9le" && !x.HasChildren); + var expect = + @"where + [HasChildren] = @p1 or [Id] <> @p2 or ([名前] = @p3 and [HasChildren] <> @p4)"; + actual.Statement.Should().Be(expect); + actual.BindParameter.Should().NotBeNull(); + actual.BindParameter.Should().Contain("p1", true); + actual.BindParameter.Should().Contain("p2", 0); + actual.BindParameter.Should().Contain("p3", "xin9le"); + actual.BindParameter.Should().Contain("p4", true); + } + */ } diff --git a/src/DeclarativeSql.Tests/Models/AccessorProvider.cs b/src/DeclarativeSql.Tests/Models/AccessorProvider.cs index 2844fb4..5c67636 100644 --- a/src/DeclarativeSql.Tests/Models/AccessorProvider.cs +++ b/src/DeclarativeSql.Tests/Models/AccessorProvider.cs @@ -2,13 +2,14 @@ using System.Collections.Generic; using System.Text; -namespace DeclarativeSql.Tests.Models +namespace DeclarativeSql.Tests.Models; + + + +public class AccessorProvider { - public class AccessorProvider - { - public string InstanceMethod() => "aaa"; - public int InstanceProperty => 31; - public static string StaticMethod() => "aaa"; - public static int StaticProperty => 31; - } + public string InstanceMethod() => "aaa"; + public int InstanceProperty => 31; + public static string StaticMethod() => "aaa"; + public static int StaticProperty => 31; } diff --git a/src/DeclarativeSql.Tests/Models/Person.cs b/src/DeclarativeSql.Tests/Models/Person.cs index 976b36c..273a474 100644 --- a/src/DeclarativeSql.Tests/Models/Person.cs +++ b/src/DeclarativeSql.Tests/Models/Person.cs @@ -1,38 +1,37 @@ using System; using DeclarativeSql.Annotations; +namespace DeclarativeSql.Tests.Models; -namespace DeclarativeSql.Tests.Models + +[Table(DbKind.SqlServer, "Person", Schema = "dbo")] +public class Person { - [Table(DbKind.SqlServer, "Person", Schema = "dbo")] - public class Person - { #pragma warning disable CS8618 - [PrimaryKey] - [AutoIncrement] - public int Id { get; set; } + [PrimaryKey] + [AutoIncrement] + public int Id { get; set; } - [Column(DbKind.SqlServer, "名前")] - public string Name { get; set; } + [Column(DbKind.SqlServer, "名前")] + public string Name { get; set; } - public int Age { get; set; } + public int Age { get; set; } - public bool HasChildren { get; set; } + public bool HasChildren { get; set; } - [CreatedAt] - [DefaultValue(DbKind.SqlServer, "SYSDATETIME()")] - public DateTimeOffset CreatedAt { get; set; } + [CreatedAt] + [DefaultValue(DbKind.SqlServer, "SYSDATETIME()")] + public DateTimeOffset CreatedAt { get; set; } - [ModifiedAt] - [Column(DbKind.MySql, "UpdatedOn")] - [DefaultValue(DbKind.MySql, "SYSDATETIME()")] - public DateTimeOffset ModifiedAt { get; set; } + [ModifiedAt] + [Column(DbKind.MySql, "UpdatedOn")] + [DefaultValue(DbKind.MySql, "SYSDATETIME()")] + public DateTimeOffset ModifiedAt { get; set; } #pragma warning restore CS8618 - } } From 7db0b94f0e47927ef56f66c9e101c90fdd5f3f33 Mon Sep 17 00:00:00 2001 From: Takaaki Suzuki Date: Wed, 10 Nov 2021 22:59:00 +0900 Subject: [PATCH 07/10] Remove unnecessary using --- src/DeclarativeSql.Tests/Models/AccessorProvider.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/DeclarativeSql.Tests/Models/AccessorProvider.cs b/src/DeclarativeSql.Tests/Models/AccessorProvider.cs index 5c67636..df0a9e6 100644 --- a/src/DeclarativeSql.Tests/Models/AccessorProvider.cs +++ b/src/DeclarativeSql.Tests/Models/AccessorProvider.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace DeclarativeSql.Tests.Models; +namespace DeclarativeSql.Tests.Models; From 110a89b1b45978ae421d482684b9ed12d452842d Mon Sep 17 00:00:00 2001 From: Takaaki Suzuki Date: Wed, 10 Nov 2021 23:21:45 +0900 Subject: [PATCH 08/10] Use file-scoped namespace in DeclarativeSql --- .../Annotations/AllowNullAttribute.cs | 25 +- .../Annotations/AutoIncrementAttribute.cs | 25 +- .../Annotations/ColumnAttribute.cs | 73 +- .../Annotations/CreatedAtAttribute.cs | 25 +- .../Annotations/DefaultValueAttribute.cs | 59 +- .../Annotations/ModifiedAtAttribute.cs | 25 +- .../Annotations/PrimaryKeyAttribute.cs | 25 +- .../Annotations/TableAttribute.cs | 71 +- .../Annotations/UniqueAttribute.cs | 37 +- src/DeclarativeSql/AvailabilityTarget.cs | 27 +- src/DeclarativeSql/DbKind.cs | 51 +- .../DbOperations/DbOperation.cs | 1098 ++-- .../DbOperations/MySqlOperation.cs | 169 +- .../DbOperations/SqlServerOperation.cs | 347 +- .../DbOperations/SqliteOperation.cs | 89 +- src/DeclarativeSql/DbProvider.cs | 251 +- .../HighAvailabilityConnection.cs | 281 +- src/DeclarativeSql/IDbConnectionExtensions.cs | 843 ++- .../Internals/EnumerableExtensions.cs | 185 +- ...EnumerableExtensions_ToFrozenDictionary.cs | 531 +- ...EnumerableExtensions_ToFrozenDictionary.tt | 103 +- .../Internals/ExpressionHelper.cs | 155 +- .../Internals/FrozenDictionary.cs | 5253 ++++++++--------- .../Internals/FrozenDictionary.tt | 555 +- .../Internals/IsExternalInit.cs | 9 +- src/DeclarativeSql/Internals/NumericHelper.cs | 51 +- src/DeclarativeSql/Internals/ReadOnlyArray.cs | 275 +- .../Internals/TypeExtensions.cs | 25 +- src/DeclarativeSql/Mapping/ColumnInfo.cs | 237 +- src/DeclarativeSql/Mapping/TableInfo.cs | 209 +- src/DeclarativeSql/Sql/BindParameter.cs | 549 +- src/DeclarativeSql/Sql/BracketPair.cs | 53 +- src/DeclarativeSql/Sql/Clauses/OrderBy.cs | 97 +- src/DeclarativeSql/Sql/Clauses/ThenBy.cs | 95 +- src/DeclarativeSql/Sql/Clauses/Where.cs | 907 ++- src/DeclarativeSql/Sql/Query.cs | 55 +- src/DeclarativeSql/Sql/QueryBuilder.cs | 869 ++- src/DeclarativeSql/Sql/Sql.cs | 25 +- src/DeclarativeSql/Sql/SqlConstants.cs | 21 +- src/DeclarativeSql/Sql/Statements/Count.cs | 37 +- src/DeclarativeSql/Sql/Statements/Delete.cs | 27 +- src/DeclarativeSql/Sql/Statements/Insert.cs | 135 +- src/DeclarativeSql/Sql/Statements/Select.cs | 99 +- src/DeclarativeSql/Sql/Statements/Truncate.cs | 27 +- src/DeclarativeSql/Sql/Statements/Update.cs | 135 +- src/DeclarativeSql/ValuePriority.cs | 27 +- 46 files changed, 7116 insertions(+), 7151 deletions(-) diff --git a/src/DeclarativeSql/Annotations/AllowNullAttribute.cs b/src/DeclarativeSql/Annotations/AllowNullAttribute.cs index 6ac3e7e..6f8c48c 100644 --- a/src/DeclarativeSql/Annotations/AllowNullAttribute.cs +++ b/src/DeclarativeSql/Annotations/AllowNullAttribute.cs @@ -1,21 +1,20 @@ using System; +namespace DeclarativeSql.Annotations; -namespace DeclarativeSql.Annotations + +/// +/// Provides an attribute that indicates whether to allow null. +/// +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)] +public sealed class AllowNullAttribute : Attribute { + #region Constructors /// - /// Provides an attribute that indicates whether to allow null. + /// Creates instance. /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)] - public sealed class AllowNullAttribute : Attribute - { - #region Constructors - /// - /// Creates instance. - /// - public AllowNullAttribute() - {} - #endregion - } + public AllowNullAttribute() + { } + #endregion } diff --git a/src/DeclarativeSql/Annotations/AutoIncrementAttribute.cs b/src/DeclarativeSql/Annotations/AutoIncrementAttribute.cs index 21ac798..1d1bea6 100644 --- a/src/DeclarativeSql/Annotations/AutoIncrementAttribute.cs +++ b/src/DeclarativeSql/Annotations/AutoIncrementAttribute.cs @@ -1,21 +1,20 @@ using System; +namespace DeclarativeSql.Annotations; -namespace DeclarativeSql.Annotations + +/// +/// Provides an attribute that indicates whether to perform automatic numbering. +/// +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)] +public sealed class AutoIncrementAttribute : Attribute { + #region Constructors /// - /// Provides an attribute that indicates whether to perform automatic numbering. + /// Creates instance. /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)] - public sealed class AutoIncrementAttribute : Attribute - { - #region Constructors - /// - /// Creates instance. - /// - public AutoIncrementAttribute() - {} - #endregion - } + public AutoIncrementAttribute() + { } + #endregion } diff --git a/src/DeclarativeSql/Annotations/ColumnAttribute.cs b/src/DeclarativeSql/Annotations/ColumnAttribute.cs index 9a1750a..ac3a836 100644 --- a/src/DeclarativeSql/Annotations/ColumnAttribute.cs +++ b/src/DeclarativeSql/Annotations/ColumnAttribute.cs @@ -1,48 +1,47 @@ using System; using System.Data; +namespace DeclarativeSql.Annotations; -namespace DeclarativeSql.Annotations + +/// +/// Provides an attribute that represents a column. +/// +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true, Inherited = true)] +public sealed class ColumnAttribute : Attribute { + #region Properties + /// + /// Gets the kind of database. + /// + public DbKind Database { get; } + + + /// + /// Gets the column name. + /// + public string Name { get; } + + + /// + /// Gets or sets the data type of the column. + /// This setting is required when performing BulkInsert under Oracle environment. + /// + public DbType? Type { get; set; } + #endregion + + + #region Constructors /// - /// Provides an attribute that represents a column. + /// Creates instance. /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true, Inherited = true)] - public sealed class ColumnAttribute : Attribute + /// + /// + public ColumnAttribute(DbKind database, string name) { - #region Properties - /// - /// Gets the kind of database. - /// - public DbKind Database { get; } - - - /// - /// Gets the column name. - /// - public string Name { get; } - - - /// - /// Gets or sets the data type of the column. - /// This setting is required when performing BulkInsert under Oracle environment. - /// - public DbType? Type { get; set; } - #endregion - - - #region Constructors - /// - /// Creates instance. - /// - /// - /// - public ColumnAttribute(DbKind database, string name) - { - this.Database = database; - this.Name = name; - } - #endregion + this.Database = database; + this.Name = name; } + #endregion } diff --git a/src/DeclarativeSql/Annotations/CreatedAtAttribute.cs b/src/DeclarativeSql/Annotations/CreatedAtAttribute.cs index 66f003d..004c4ec 100644 --- a/src/DeclarativeSql/Annotations/CreatedAtAttribute.cs +++ b/src/DeclarativeSql/Annotations/CreatedAtAttribute.cs @@ -1,21 +1,20 @@ using System; +namespace DeclarativeSql.Annotations; -namespace DeclarativeSql.Annotations + +/// +/// Provides an attribute that indicates whether is CreatedAt column. +/// +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)] +public sealed class CreatedAtAttribute : Attribute { + #region Constructors /// - /// Provides an attribute that indicates whether is CreatedAt column. + /// Creates instance. /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)] - public sealed class CreatedAtAttribute : Attribute - { - #region Constructors - /// - /// Creates instance. - /// - public CreatedAtAttribute() - { } - #endregion - } + public CreatedAtAttribute() + { } + #endregion } diff --git a/src/DeclarativeSql/Annotations/DefaultValueAttribute.cs b/src/DeclarativeSql/Annotations/DefaultValueAttribute.cs index 8164f37..b3acf64 100644 --- a/src/DeclarativeSql/Annotations/DefaultValueAttribute.cs +++ b/src/DeclarativeSql/Annotations/DefaultValueAttribute.cs @@ -1,40 +1,39 @@ using System; +namespace DeclarativeSql.Annotations; -namespace DeclarativeSql.Annotations + +/// +/// Provides an attribute that represents default value of column. +/// +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true, Inherited = true)] +public sealed class DefaultValueAttribute : Attribute { + #region Properties + /// + /// Gets the kind of database. + /// + public DbKind Database { get; } + + + /// + /// Gets the default value. + /// + public object Value { get; } + #endregion + + + #region Constructors /// - /// Provides an attribute that represents default value of column. + /// Creates instance. /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true, Inherited = true)] - public sealed class DefaultValueAttribute : Attribute + /// + /// + public DefaultValueAttribute(DbKind database, object value) { - #region Properties - /// - /// Gets the kind of database. - /// - public DbKind Database { get; } - - - /// - /// Gets the default value. - /// - public object Value { get; } - #endregion - - - #region Constructors - /// - /// Creates instance. - /// - /// - /// - public DefaultValueAttribute(DbKind database, object value) - { - this.Database = database; - this.Value = value; - } - #endregion + this.Database = database; + this.Value = value; } + #endregion } diff --git a/src/DeclarativeSql/Annotations/ModifiedAtAttribute.cs b/src/DeclarativeSql/Annotations/ModifiedAtAttribute.cs index 7131600..35981ac 100644 --- a/src/DeclarativeSql/Annotations/ModifiedAtAttribute.cs +++ b/src/DeclarativeSql/Annotations/ModifiedAtAttribute.cs @@ -1,21 +1,20 @@ using System; +namespace DeclarativeSql.Annotations; -namespace DeclarativeSql.Annotations + +/// +/// Provides an attribute that indicates whether is ModifiedAt column. +/// +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)] +public sealed class ModifiedAtAttribute : Attribute { + #region Constructors /// - /// Provides an attribute that indicates whether is ModifiedAt column. + /// Creates instance. /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)] - public sealed class ModifiedAtAttribute : Attribute - { - #region Constructors - /// - /// Creates instance. - /// - public ModifiedAtAttribute() - { } - #endregion - } + public ModifiedAtAttribute() + { } + #endregion } diff --git a/src/DeclarativeSql/Annotations/PrimaryKeyAttribute.cs b/src/DeclarativeSql/Annotations/PrimaryKeyAttribute.cs index 2499041..9933c71 100644 --- a/src/DeclarativeSql/Annotations/PrimaryKeyAttribute.cs +++ b/src/DeclarativeSql/Annotations/PrimaryKeyAttribute.cs @@ -1,21 +1,20 @@ using System; +namespace DeclarativeSql.Annotations; -namespace DeclarativeSql.Annotations + +/// +/// Provides an attribute that represents a primary key. +/// +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)] +public sealed class PrimaryKeyAttribute : Attribute { + #region Constructors /// - /// Provides an attribute that represents a primary key. + /// Creates instance. /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)] - public sealed class PrimaryKeyAttribute : Attribute - { - #region Constructors - /// - /// Creates instance. - /// - public PrimaryKeyAttribute() - {} - #endregion - } + public PrimaryKeyAttribute() + { } + #endregion } diff --git a/src/DeclarativeSql/Annotations/TableAttribute.cs b/src/DeclarativeSql/Annotations/TableAttribute.cs index f0fef5c..63a4ddf 100644 --- a/src/DeclarativeSql/Annotations/TableAttribute.cs +++ b/src/DeclarativeSql/Annotations/TableAttribute.cs @@ -1,46 +1,45 @@ using System; +namespace DeclarativeSql.Annotations; -namespace DeclarativeSql.Annotations + +/// +/// Provides an attribute that represents a table. +/// +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true, Inherited = true)] +public sealed class TableAttribute : Attribute { + #region Properties + /// + /// Gets the kind of database. + /// + public DbKind Database { get; } + + + /// + /// Gets the table name. + /// + public string Name { get; } + + + /// + /// Gets or sets the schema name. + /// + public string? Schema { get; set; } + #endregion + + + #region Constructors /// - /// Provides an attribute that represents a table. + /// Creates instance. /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true, Inherited = true)] - public sealed class TableAttribute : Attribute + /// + /// + public TableAttribute(DbKind database, string name) { - #region Properties - /// - /// Gets the kind of database. - /// - public DbKind Database { get; } - - - /// - /// Gets the table name. - /// - public string Name { get; } - - - /// - /// Gets or sets the schema name. - /// - public string? Schema { get; set; } - #endregion - - - #region Constructors - /// - /// Creates instance. - /// - /// - /// - public TableAttribute(DbKind database, string name) - { - this.Database = database; - this.Name = name; - } - #endregion + this.Database = database; + this.Name = name; } + #endregion } diff --git a/src/DeclarativeSql/Annotations/UniqueAttribute.cs b/src/DeclarativeSql/Annotations/UniqueAttribute.cs index af68ff3..81b9501 100644 --- a/src/DeclarativeSql/Annotations/UniqueAttribute.cs +++ b/src/DeclarativeSql/Annotations/UniqueAttribute.cs @@ -1,29 +1,28 @@ using System; +namespace DeclarativeSql.Annotations; -namespace DeclarativeSql.Annotations + +/// +/// Provides an attribute that represents a unique constraint. +/// +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)] +public sealed class UniqueAttribute : Attribute { + #region Properties /// - /// Provides an attribute that represents a unique constraint. + /// Gets the index. /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)] - public sealed class UniqueAttribute : Attribute - { - #region Properties - /// - /// Gets the index. - /// - public ushort Index { get; } - #endregion + public ushort Index { get; } + #endregion - #region Constructors - /// - /// Creates instance. - /// - public UniqueAttribute(ushort index) - => this.Index = index; - #endregion - } + #region Constructors + /// + /// Creates instance. + /// + public UniqueAttribute(ushort index) + => this.Index = index; + #endregion } diff --git a/src/DeclarativeSql/AvailabilityTarget.cs b/src/DeclarativeSql/AvailabilityTarget.cs index ee4e9ce..6946bf1 100644 --- a/src/DeclarativeSql/AvailabilityTarget.cs +++ b/src/DeclarativeSql/AvailabilityTarget.cs @@ -1,18 +1,19 @@ -namespace DeclarativeSql +namespace DeclarativeSql; + + + +/// +/// Represents the availability database reference. +/// +public enum AvailabilityTarget { /// - /// Represents the availability database reference. + /// Master /// - public enum AvailabilityTarget - { - /// - /// Master - /// - Master = 0, + Master = 0, - /// - /// Slave - /// - Slave, - } + /// + /// Slave + /// + Slave, } diff --git a/src/DeclarativeSql/DbKind.cs b/src/DeclarativeSql/DbKind.cs index a828aba..b56bc09 100644 --- a/src/DeclarativeSql/DbKind.cs +++ b/src/DeclarativeSql/DbKind.cs @@ -1,33 +1,34 @@ -namespace DeclarativeSql +namespace DeclarativeSql; + + + +/// +/// Represents kind of database. +/// +public enum DbKind { /// - /// Represents kind of database. + /// SQL Server /// - public enum DbKind - { - /// - /// SQL Server - /// - SqlServer = 0, + SqlServer = 0, - /// - /// MySQL / Amazon Aurora / MariaDB - /// - MySql, + /// + /// MySQL / Amazon Aurora / MariaDB + /// + MySql, - /// - /// SQLite - /// - Sqlite, + /// + /// SQLite + /// + Sqlite, - /// - /// PostgreSQL - /// - PostgreSql, + /// + /// PostgreSQL + /// + PostgreSql, - /// - /// Oracle - /// - Oracle, - } + /// + /// Oracle + /// + Oracle, } diff --git a/src/DeclarativeSql/DbOperations/DbOperation.cs b/src/DeclarativeSql/DbOperations/DbOperation.cs index 8f089f4..37e4b48 100644 --- a/src/DeclarativeSql/DbOperations/DbOperation.cs +++ b/src/DeclarativeSql/DbOperations/DbOperation.cs @@ -7,583 +7,581 @@ using Dapper; using DeclarativeSql.Sql; +namespace DeclarativeSql.DbOperations; +using Ctor = Func; -namespace DeclarativeSql.DbOperations + + +/// +/// Provides database operations. +/// +internal class DbOperation { - using Ctor = Func; + #region Properties + /// + /// Gets the database connection. + /// + protected IDbConnection Connection { get; } /// - /// Provides database operations. + /// Gets the database transaction. /// - internal class DbOperation - { - #region Properties - /// - /// Gets the database connection. - /// - protected IDbConnection Connection { get; } + protected IDbTransaction? Transaction { get; } - /// - /// Gets the database transaction. - /// - protected IDbTransaction? Transaction { get; } + /// + /// Gets the database provider. + /// + protected DbProvider DbProvider { get; } - /// - /// Gets the database provider. - /// - protected DbProvider DbProvider { get; } + /// + /// Gets the operation timeout. + /// + protected int? Timeout { get; } - /// - /// Gets the operation timeout. - /// - protected int? Timeout { get; } + /// + /// Gets the factory by database connection type. + /// + internal static Dictionary Factory { get; } + = new Dictionary(); + #endregion - /// - /// Gets the factory by database connection type. - /// - internal static Dictionary Factory { get; } - = new Dictionary(); - #endregion + #region Constructors + /// + /// Creates instance. + /// + /// + /// + /// + /// + protected DbOperation(IDbConnection connection, IDbTransaction? transaction, DbProvider provider, int? timeout) + { + this.Connection = connection; + this.Transaction = transaction; + this.DbProvider = provider; + this.Timeout = timeout; + } + #endregion - #region Constructors - /// - /// Creates instance. - /// - /// - /// - /// - /// - protected DbOperation(IDbConnection connection, IDbTransaction? transaction, DbProvider provider, int? timeout) - { - this.Connection = connection; - this.Transaction = transaction; - this.DbProvider = provider; - this.Timeout = timeout; - } - #endregion - - - #region Create - /// - /// Creates instance. - /// - /// - /// - /// - public static DbOperation Create(IDbConnection connection, int? timeout) - => Create(connection, null, timeout); - - - /// - /// Creates instance. - /// - /// - /// - /// - public static DbOperation Create(IDbTransaction transaction, int? timeout) - { - if (transaction.Connection is null) - throw new ArgumentException("IDbTransaction.Connection is null."); - return Create(transaction.Connection, transaction, timeout); - } - - - /// - /// Creates instance. - /// - /// - /// - /// - /// - private static DbOperation Create(IDbConnection connection, IDbTransaction? transaction, int? timeout) + #region Create + /// + /// Creates instance. + /// + /// + /// + /// + public static DbOperation Create(IDbConnection connection, int? timeout) + => Create(connection, null, timeout); + + + /// + /// Creates instance. + /// + /// + /// + /// + public static DbOperation Create(IDbTransaction transaction, int? timeout) + { + if (transaction.Connection is null) + throw new ArgumentException("IDbTransaction.Connection is null."); + return Create(transaction.Connection, transaction, timeout); + } + + + /// + /// Creates instance. + /// + /// + /// + /// + /// + private static DbOperation Create(IDbConnection connection, IDbTransaction? transaction, int? timeout) + { + //--- override + var type = connection.GetType(); + if (Factory.TryGetValue(type, out var ctor)) + return ctor(connection, transaction, timeout); + + //--- default + return type.FullName switch { - //--- override - var type = connection.GetType(); - if (Factory.TryGetValue(type, out var ctor)) - return ctor(connection, transaction, timeout); + "System.Data.SqlClient.SqlConnection" + => new SqlServerOperation(connection, transaction, DbProvider.SqlServer, timeout), - //--- default - return type.FullName switch - { - "System.Data.SqlClient.SqlConnection" - => new SqlServerOperation(connection, transaction, DbProvider.SqlServer, timeout), + "Microsoft.Data.SqlClient.SqlConnection" + => new SqlServerOperation(connection, transaction, DbProvider.SqlServer, timeout), - "Microsoft.Data.SqlClient.SqlConnection" - => new SqlServerOperation(connection, transaction, DbProvider.SqlServer, timeout), + "MySqlConnector.MySqlConnection" + => new MySqlOperation(connection, transaction, DbProvider.MySql, timeout), - "MySqlConnector.MySqlConnection" - => new MySqlOperation(connection, transaction, DbProvider.MySql, timeout), + "MySql.Data.MySqlClient.MySqlConnection" + => new MySqlOperation(connection, transaction, DbProvider.MySql, timeout), - "MySql.Data.MySqlClient.MySqlConnection" - => new MySqlOperation(connection, transaction, DbProvider.MySql, timeout), + "Microsoft.Data.Sqlite.SqliteConnection" + => new SqliteOperation(connection, transaction, DbProvider.Sqlite, timeout), - "Microsoft.Data.Sqlite.SqliteConnection" - => new SqliteOperation(connection, transaction, DbProvider.Sqlite, timeout), + "Npgsql.NpgsqlConnection" + => new DbOperation(connection, transaction, DbProvider.PostgreSql, timeout), - "Npgsql.NpgsqlConnection" - => new DbOperation(connection, transaction, DbProvider.PostgreSql, timeout), + "Oracle.ManagedDataAccess.Client.OracleConnection" + => new DbOperation(connection, transaction, DbProvider.Oracle, timeout), - "Oracle.ManagedDataAccess.Client.OracleConnection" - => new DbOperation(connection, transaction, DbProvider.Oracle, timeout), + _ => throw new NotSupportedException(), + }; + } + #endregion - _ => throw new NotSupportedException(), - }; - } - #endregion + #region Count + /// + /// Gets the number of records in the specified table. + /// + /// + /// Record count + public virtual ulong Count() + { + var query = QueryBuilder.Count(this.DbProvider); + return this.Connection.ExecuteScalar(query.Statement, query.BindParameter, this.Transaction, this.Timeout); + } - #region Count - /// - /// Gets the number of records in the specified table. - /// - /// - /// Record count - public virtual ulong Count() - { - var query = QueryBuilder.Count(this.DbProvider); - return this.Connection.ExecuteScalar(query.Statement, query.BindParameter, this.Transaction, this.Timeout); - } - - - /// - /// Gets the number of records that match the specified condition in the specified table. - /// - /// - /// - /// Record count - public virtual ulong Count(Expression> predicate) - { - var query = QueryBuilder.Count(this.DbProvider, predicate); - return this.Connection.ExecuteScalar(query.Statement, query.BindParameter, this.Transaction, this.Timeout); - } - - - /// - /// Gets the number of records in the specified table. - /// - /// - /// - /// Record count - public virtual Task CountAsync(CancellationToken cancellationToken) - { - var query = QueryBuilder.Count(this.DbProvider); - var command = new CommandDefinition(query.Statement, query.BindParameter, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); - return this.Connection.ExecuteScalarAsync(command); - } - - - /// - /// Gets the number of records that match the specified condition in the specified table. - /// - /// - /// - /// - /// Record count - public virtual Task CountAsync(Expression> predicate, CancellationToken cancellationToken) - { - var query = QueryBuilder.Count(this.DbProvider, predicate); - var command = new CommandDefinition(query.Statement, query.BindParameter, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); - return this.Connection.ExecuteScalarAsync(command); - } - #endregion - - - #region Select - /// - /// Gets all records from the specified table. - /// - /// - /// - /// - public virtual List Select(Expression>? properties) - { - var query = QueryBuilder.Select(this.DbProvider, properties); - return (List)this.Connection.Query(query.Statement, query.BindParameter, this.Transaction, true, this.Timeout); - } - - - /// - /// Gets records that match the specified condition from the specified table. - /// - /// - /// - /// - /// - public virtual List Select(Expression> predicate, Expression>? properties) - { - var query = QueryBuilder.Select(this.DbProvider, predicate, properties); - return (List)this.Connection.Query(query.Statement, query.BindParameter, this.Transaction, true, this.Timeout); - } - - - /// - /// Gets all records from the specified table. - /// - /// - /// - /// - /// - public virtual async Task> SelectAsync(Expression>? properties, CancellationToken cancellationToken) - { - var query = QueryBuilder.Select(this.DbProvider, properties); - var command = new CommandDefinition(query.Statement, query.BindParameter, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); - var result = await this.Connection.QueryAsync(command).ConfigureAwait(false); - return (List)result; - } - - - /// - /// Gets records that match the specified condition from the specified table. - /// - /// - /// - /// - /// - /// - public virtual async Task> SelectAsync(Expression> predicate, Expression>? properties, CancellationToken cancellationToken) - { - var query = QueryBuilder.Select(this.DbProvider, predicate, properties); - var command = new CommandDefinition(query.Statement, query.BindParameter, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); - var result = await this.Connection.QueryAsync(command).ConfigureAwait(false); - return (List)result; - } - #endregion - - - #region Insert - /// - /// Inserts the specified data into the table. - /// - /// - /// - /// - /// Effected rows count - public virtual int Insert(T data, ValuePriority createdAt) - { - var query = QueryBuilder.Insert(this.DbProvider, createdAt); - return this.Connection.Execute(query.Statement, data, this.Transaction, this.Timeout); - } - - - /// - /// Inserts the specified data into the table. - /// - /// - /// - /// - /// - /// Effected rows count - public virtual Task InsertAsync(T data, ValuePriority createdAt, CancellationToken cancellationToken) - { - var query = QueryBuilder.Insert(this.DbProvider, createdAt); - var command = new CommandDefinition(query.Statement, data, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); - return this.Connection.ExecuteAsync(command); - } - #endregion - - - #region InsertMulti - /// - /// Inserts the specified data into the table. - /// - /// - /// - /// - /// Effected rows count - public virtual int InsertMulti(IEnumerable data, ValuePriority createdAt) - { - var query = QueryBuilder.Insert(this.DbProvider, createdAt); - return this.Connection.Execute(query.Statement, data, this.Transaction, this.Timeout); - } - - - /// - /// Inserts the specified data into the table. - /// - /// - /// - /// - /// - /// Effected rows count - public virtual Task InsertMultiAsync(IEnumerable data, ValuePriority createdAt, CancellationToken cancellationToken) - { - var query = QueryBuilder.Insert(this.DbProvider, createdAt); - var command = new CommandDefinition(query.Statement, data, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); - return this.Connection.ExecuteAsync(command); - } - #endregion - - - #region BulkInsert - /// - /// Inserts the specified data into the table using the bulk method. - /// - /// - /// - /// - /// Effected rows count - public virtual int BulkInsert(IEnumerable data, ValuePriority createdAt) - => throw new NotSupportedException(); - - - /// - /// Inserts the specified data into the table using the bulk method. - /// - /// - /// - /// - /// - /// Effected rows count - public virtual Task BulkInsertAsync(IEnumerable data, ValuePriority createdAt, CancellationToken cancellationToken) - => throw new NotSupportedException(); - #endregion - - - #region InsertAndGetId - /// - /// Inserts the specified data into the table and returns the automatically incremented ID. - /// - /// - /// - /// - /// Auto incremented ID - public virtual long InsertAndGetId(T data, ValuePriority createdAt) - => throw new NotSupportedException(); - - - /// - /// Inserts the specified data into the table and returns the automatically incremented ID. - /// - /// - /// - /// - /// - /// Auto incremented ID - public virtual Task InsertAndGetIdAsync(T data, ValuePriority createdAt, CancellationToken cancellationToken) - => throw new NotSupportedException(); - #endregion - - - #region InsertIgnore - /// - /// Inserts the specified data into the table. - /// Insertion processing is not performed when there is a collision with a unique constraint. - /// - /// - /// - /// - /// Effected row count - public virtual int InsertIgnore(T data, ValuePriority createdAt) - => throw new NotSupportedException(); - - - /// - /// Inserts the specified data into the table. - /// Insertion processing is not performed when there is a collision with a unique constraint. - /// - /// - /// - /// - /// - /// Effected row count - public virtual Task InsertIgnoreAsync(T data, ValuePriority createdAt, CancellationToken cancellationToken) - => throw new NotSupportedException(); - #endregion - - - #region InsertIgnoreMulti - /// - /// Inserts the specified data into the table. - /// Insertion processing is not performed when there is a collision with a unique constraint. - /// - /// - /// - /// - /// Effected row count - public virtual int InsertIgnoreMulti(IEnumerable data, ValuePriority createdAt) - => throw new NotSupportedException(); - - - /// - /// Inserts the specified data into the table. - /// Insertion processing is not performed when there is a collision with a unique constraint. - /// - /// - /// - /// - /// - /// Effected row count - public virtual Task InsertIgnoreMultiAsync(IEnumerable data, ValuePriority createdAt, CancellationToken cancellationToken) - => throw new NotSupportedException(); - #endregion - - - #region Update - /// - /// Updates records with the specified data. - /// - /// - /// - /// - /// - /// Effected rows count - public virtual int Update(T data, Expression>? properties, ValuePriority modifiedAt) - { - var query = QueryBuilder.Update(this.DbProvider, properties, modifiedAt); - if (query.BindParameter is not null) - query.BindParameter.Overwrite(data); - return this.Connection.Execute(query.Statement, query.BindParameter, this.Transaction, this.Timeout); - } - - - /// - /// Updates records that match the specified conditions with the specified data. - /// - /// - /// - /// - /// - /// - /// Effected rows count - public virtual int Update(T data, Expression> predicate, Expression>? properties, ValuePriority modifiedAt) - { - var query = QueryBuilder.Update(this.DbProvider, predicate, properties, modifiedAt); - if (query.BindParameter is not null) - query.BindParameter.Overwrite(data); - return this.Connection.Execute(query.Statement, query.BindParameter, this.Transaction, this.Timeout); - } - - - /// - /// Updates records with the specified data. - /// - /// - /// - /// - /// - /// - /// Effected rows count - public virtual Task UpdateAsync(T data, Expression>? properties, ValuePriority modifiedAt, CancellationToken cancellationToken) - { - var query = QueryBuilder.Update(this.DbProvider, properties, modifiedAt); - if (query.BindParameter is not null) - query.BindParameter.Overwrite(data); - - var command = new CommandDefinition(query.Statement, query.BindParameter, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); - return this.Connection.ExecuteAsync(command); - } - - - /// - /// Updates records that match the specified conditions with the specified data. - /// - /// - /// - /// - /// - /// - /// - /// Effected rows count - public virtual Task UpdateAsync(T data, Expression> predicate, Expression>? properties, ValuePriority modifiedAt, CancellationToken cancellationToken) - { - var query = QueryBuilder.Update(this.DbProvider, predicate, properties, modifiedAt); - if (query.BindParameter is not null) - query.BindParameter.Overwrite(data); - - var command = new CommandDefinition(query.Statement, query.BindParameter, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); - return this.Connection.ExecuteAsync(command); - } - #endregion - - - #region Delete - /// - /// Deletes all records from the specified table. - /// - /// - /// Effected rows count - public virtual int Delete() - { - var query = QueryBuilder.Delete(this.DbProvider); - return this.Connection.Execute(query.Statement, query.BindParameter, this.Transaction, this.Timeout); - } - - - /// - /// Deletes records that match the specified conditions from the specified table. - /// - /// - /// - /// Effected rows count - public virtual int Delete(Expression> predicate) - { - var query = QueryBuilder.Delete(this.DbProvider, predicate); - return this.Connection.Execute(query.Statement, query.BindParameter, this.Transaction, this.Timeout); - } - - - /// - /// Deletes all records from the specified table. - /// - /// - /// - /// Effected rows count - public virtual Task DeleteAsync(CancellationToken cancellationToken) - { - var query = QueryBuilder.Delete(this.DbProvider); - var command = new CommandDefinition(query.Statement, query.BindParameter, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); - return this.Connection.ExecuteAsync(command); - } - - - /// - /// Deletes records that match the specified conditions from the specified table. - /// - /// - /// - /// - /// Effected rows count - public virtual Task DeleteAsync(Expression> predicate, CancellationToken cancellationToken) - { - var query = QueryBuilder.Delete(this.DbProvider, predicate); - var command = new CommandDefinition(query.Statement, query.BindParameter, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); - return this.Connection.ExecuteAsync(command); - } - #endregion - - - #region Truncate - /// - /// Truncates the specified table. - /// - /// - /// -1 - public virtual int Truncate() - { - var query = QueryBuilder.Truncate(this.DbProvider); - return this.Connection.Execute(query.Statement, query.BindParameter, this.Transaction, this.Timeout); - } - - - /// - /// Truncates the specified table. - /// - /// - /// - /// -1 - public virtual Task TruncateAsync(CancellationToken cancellationToken) - { - var query = QueryBuilder.Truncate(this.DbProvider); - var command = new CommandDefinition(query.Statement, query.BindParameter, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); - return this.Connection.ExecuteAsync(command); - } - #endregion + + /// + /// Gets the number of records that match the specified condition in the specified table. + /// + /// + /// + /// Record count + public virtual ulong Count(Expression> predicate) + { + var query = QueryBuilder.Count(this.DbProvider, predicate); + return this.Connection.ExecuteScalar(query.Statement, query.BindParameter, this.Transaction, this.Timeout); + } + + + /// + /// Gets the number of records in the specified table. + /// + /// + /// + /// Record count + public virtual Task CountAsync(CancellationToken cancellationToken) + { + var query = QueryBuilder.Count(this.DbProvider); + var command = new CommandDefinition(query.Statement, query.BindParameter, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); + return this.Connection.ExecuteScalarAsync(command); + } + + + /// + /// Gets the number of records that match the specified condition in the specified table. + /// + /// + /// + /// + /// Record count + public virtual Task CountAsync(Expression> predicate, CancellationToken cancellationToken) + { + var query = QueryBuilder.Count(this.DbProvider, predicate); + var command = new CommandDefinition(query.Statement, query.BindParameter, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); + return this.Connection.ExecuteScalarAsync(command); + } + #endregion + + + #region Select + /// + /// Gets all records from the specified table. + /// + /// + /// + /// + public virtual List Select(Expression>? properties) + { + var query = QueryBuilder.Select(this.DbProvider, properties); + return (List)this.Connection.Query(query.Statement, query.BindParameter, this.Transaction, true, this.Timeout); + } + + + /// + /// Gets records that match the specified condition from the specified table. + /// + /// + /// + /// + /// + public virtual List Select(Expression> predicate, Expression>? properties) + { + var query = QueryBuilder.Select(this.DbProvider, predicate, properties); + return (List)this.Connection.Query(query.Statement, query.BindParameter, this.Transaction, true, this.Timeout); + } + + + /// + /// Gets all records from the specified table. + /// + /// + /// + /// + /// + public virtual async Task> SelectAsync(Expression>? properties, CancellationToken cancellationToken) + { + var query = QueryBuilder.Select(this.DbProvider, properties); + var command = new CommandDefinition(query.Statement, query.BindParameter, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); + var result = await this.Connection.QueryAsync(command).ConfigureAwait(false); + return (List)result; + } + + + /// + /// Gets records that match the specified condition from the specified table. + /// + /// + /// + /// + /// + /// + public virtual async Task> SelectAsync(Expression> predicate, Expression>? properties, CancellationToken cancellationToken) + { + var query = QueryBuilder.Select(this.DbProvider, predicate, properties); + var command = new CommandDefinition(query.Statement, query.BindParameter, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); + var result = await this.Connection.QueryAsync(command).ConfigureAwait(false); + return (List)result; + } + #endregion + + + #region Insert + /// + /// Inserts the specified data into the table. + /// + /// + /// + /// + /// Effected rows count + public virtual int Insert(T data, ValuePriority createdAt) + { + var query = QueryBuilder.Insert(this.DbProvider, createdAt); + return this.Connection.Execute(query.Statement, data, this.Transaction, this.Timeout); + } + + + /// + /// Inserts the specified data into the table. + /// + /// + /// + /// + /// + /// Effected rows count + public virtual Task InsertAsync(T data, ValuePriority createdAt, CancellationToken cancellationToken) + { + var query = QueryBuilder.Insert(this.DbProvider, createdAt); + var command = new CommandDefinition(query.Statement, data, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); + return this.Connection.ExecuteAsync(command); + } + #endregion + + + #region InsertMulti + /// + /// Inserts the specified data into the table. + /// + /// + /// + /// + /// Effected rows count + public virtual int InsertMulti(IEnumerable data, ValuePriority createdAt) + { + var query = QueryBuilder.Insert(this.DbProvider, createdAt); + return this.Connection.Execute(query.Statement, data, this.Transaction, this.Timeout); + } + + + /// + /// Inserts the specified data into the table. + /// + /// + /// + /// + /// + /// Effected rows count + public virtual Task InsertMultiAsync(IEnumerable data, ValuePriority createdAt, CancellationToken cancellationToken) + { + var query = QueryBuilder.Insert(this.DbProvider, createdAt); + var command = new CommandDefinition(query.Statement, data, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); + return this.Connection.ExecuteAsync(command); + } + #endregion + + + #region BulkInsert + /// + /// Inserts the specified data into the table using the bulk method. + /// + /// + /// + /// + /// Effected rows count + public virtual int BulkInsert(IEnumerable data, ValuePriority createdAt) + => throw new NotSupportedException(); + + + /// + /// Inserts the specified data into the table using the bulk method. + /// + /// + /// + /// + /// + /// Effected rows count + public virtual Task BulkInsertAsync(IEnumerable data, ValuePriority createdAt, CancellationToken cancellationToken) + => throw new NotSupportedException(); + #endregion + + + #region InsertAndGetId + /// + /// Inserts the specified data into the table and returns the automatically incremented ID. + /// + /// + /// + /// + /// Auto incremented ID + public virtual long InsertAndGetId(T data, ValuePriority createdAt) + => throw new NotSupportedException(); + + + /// + /// Inserts the specified data into the table and returns the automatically incremented ID. + /// + /// + /// + /// + /// + /// Auto incremented ID + public virtual Task InsertAndGetIdAsync(T data, ValuePriority createdAt, CancellationToken cancellationToken) + => throw new NotSupportedException(); + #endregion + + + #region InsertIgnore + /// + /// Inserts the specified data into the table. + /// Insertion processing is not performed when there is a collision with a unique constraint. + /// + /// + /// + /// + /// Effected row count + public virtual int InsertIgnore(T data, ValuePriority createdAt) + => throw new NotSupportedException(); + + + /// + /// Inserts the specified data into the table. + /// Insertion processing is not performed when there is a collision with a unique constraint. + /// + /// + /// + /// + /// + /// Effected row count + public virtual Task InsertIgnoreAsync(T data, ValuePriority createdAt, CancellationToken cancellationToken) + => throw new NotSupportedException(); + #endregion + + + #region InsertIgnoreMulti + /// + /// Inserts the specified data into the table. + /// Insertion processing is not performed when there is a collision with a unique constraint. + /// + /// + /// + /// + /// Effected row count + public virtual int InsertIgnoreMulti(IEnumerable data, ValuePriority createdAt) + => throw new NotSupportedException(); + + + /// + /// Inserts the specified data into the table. + /// Insertion processing is not performed when there is a collision with a unique constraint. + /// + /// + /// + /// + /// + /// Effected row count + public virtual Task InsertIgnoreMultiAsync(IEnumerable data, ValuePriority createdAt, CancellationToken cancellationToken) + => throw new NotSupportedException(); + #endregion + + + #region Update + /// + /// Updates records with the specified data. + /// + /// + /// + /// + /// + /// Effected rows count + public virtual int Update(T data, Expression>? properties, ValuePriority modifiedAt) + { + var query = QueryBuilder.Update(this.DbProvider, properties, modifiedAt); + if (query.BindParameter is not null) + query.BindParameter.Overwrite(data); + return this.Connection.Execute(query.Statement, query.BindParameter, this.Transaction, this.Timeout); + } + + + /// + /// Updates records that match the specified conditions with the specified data. + /// + /// + /// + /// + /// + /// + /// Effected rows count + public virtual int Update(T data, Expression> predicate, Expression>? properties, ValuePriority modifiedAt) + { + var query = QueryBuilder.Update(this.DbProvider, predicate, properties, modifiedAt); + if (query.BindParameter is not null) + query.BindParameter.Overwrite(data); + return this.Connection.Execute(query.Statement, query.BindParameter, this.Transaction, this.Timeout); + } + + + /// + /// Updates records with the specified data. + /// + /// + /// + /// + /// + /// + /// Effected rows count + public virtual Task UpdateAsync(T data, Expression>? properties, ValuePriority modifiedAt, CancellationToken cancellationToken) + { + var query = QueryBuilder.Update(this.DbProvider, properties, modifiedAt); + if (query.BindParameter is not null) + query.BindParameter.Overwrite(data); + + var command = new CommandDefinition(query.Statement, query.BindParameter, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); + return this.Connection.ExecuteAsync(command); + } + + + /// + /// Updates records that match the specified conditions with the specified data. + /// + /// + /// + /// + /// + /// + /// + /// Effected rows count + public virtual Task UpdateAsync(T data, Expression> predicate, Expression>? properties, ValuePriority modifiedAt, CancellationToken cancellationToken) + { + var query = QueryBuilder.Update(this.DbProvider, predicate, properties, modifiedAt); + if (query.BindParameter is not null) + query.BindParameter.Overwrite(data); + + var command = new CommandDefinition(query.Statement, query.BindParameter, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); + return this.Connection.ExecuteAsync(command); + } + #endregion + + + #region Delete + /// + /// Deletes all records from the specified table. + /// + /// + /// Effected rows count + public virtual int Delete() + { + var query = QueryBuilder.Delete(this.DbProvider); + return this.Connection.Execute(query.Statement, query.BindParameter, this.Transaction, this.Timeout); + } + + + /// + /// Deletes records that match the specified conditions from the specified table. + /// + /// + /// + /// Effected rows count + public virtual int Delete(Expression> predicate) + { + var query = QueryBuilder.Delete(this.DbProvider, predicate); + return this.Connection.Execute(query.Statement, query.BindParameter, this.Transaction, this.Timeout); + } + + + /// + /// Deletes all records from the specified table. + /// + /// + /// + /// Effected rows count + public virtual Task DeleteAsync(CancellationToken cancellationToken) + { + var query = QueryBuilder.Delete(this.DbProvider); + var command = new CommandDefinition(query.Statement, query.BindParameter, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); + return this.Connection.ExecuteAsync(command); + } + + + /// + /// Deletes records that match the specified conditions from the specified table. + /// + /// + /// + /// + /// Effected rows count + public virtual Task DeleteAsync(Expression> predicate, CancellationToken cancellationToken) + { + var query = QueryBuilder.Delete(this.DbProvider, predicate); + var command = new CommandDefinition(query.Statement, query.BindParameter, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); + return this.Connection.ExecuteAsync(command); + } + #endregion + + + #region Truncate + /// + /// Truncates the specified table. + /// + /// + /// -1 + public virtual int Truncate() + { + var query = QueryBuilder.Truncate(this.DbProvider); + return this.Connection.Execute(query.Statement, query.BindParameter, this.Transaction, this.Timeout); + } + + + /// + /// Truncates the specified table. + /// + /// + /// + /// -1 + public virtual Task TruncateAsync(CancellationToken cancellationToken) + { + var query = QueryBuilder.Truncate(this.DbProvider); + var command = new CommandDefinition(query.Statement, query.BindParameter, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); + return this.Connection.ExecuteAsync(command); } + #endregion } diff --git a/src/DeclarativeSql/DbOperations/MySqlOperation.cs b/src/DeclarativeSql/DbOperations/MySqlOperation.cs index 190e7d7..6535cbf 100644 --- a/src/DeclarativeSql/DbOperations/MySqlOperation.cs +++ b/src/DeclarativeSql/DbOperations/MySqlOperation.cs @@ -6,111 +6,110 @@ using Dapper; using DeclarativeSql.Sql; +namespace DeclarativeSql.DbOperations; -namespace DeclarativeSql.DbOperations + +/// +/// Provides MySQL specific database operation. +/// +internal class MySqlOperation : DbOperation { - /// - /// Provides MySQL specific database operation. - /// - internal class MySqlOperation : DbOperation - { - #region Constructors - /// - public MySqlOperation(IDbConnection connection, IDbTransaction? transaction, DbProvider provider, int? timeout) - : base(connection, transaction, provider, timeout) - { } - #endregion + #region Constructors + /// + public MySqlOperation(IDbConnection connection, IDbTransaction? transaction, DbProvider provider, int? timeout) + : base(connection, transaction, provider, timeout) + { } + #endregion - #region InsertAndGetId - /// - public override long InsertAndGetId(T data, ValuePriority createdAt) - { - var sql = this.CreateInsertAndGetIdSql(createdAt); - var reader = this.Connection.QueryMultiple(sql, data, this.Transaction, this.Timeout); - return (long)reader.Read().First().Id; - } + #region InsertAndGetId + /// + public override long InsertAndGetId(T data, ValuePriority createdAt) + { + var sql = this.CreateInsertAndGetIdSql(createdAt); + var reader = this.Connection.QueryMultiple(sql, data, this.Transaction, this.Timeout); + return (long)reader.Read().First().Id; + } - /// - public override async Task InsertAndGetIdAsync(T data, ValuePriority createdAt, CancellationToken cancellationToken) - { - var sql = this.CreateInsertAndGetIdSql(createdAt); - var command = new CommandDefinition(sql, data, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); - var reader = await this.Connection.QueryMultipleAsync(command).ConfigureAwait(false); - var results = await reader.ReadAsync().ConfigureAwait(false); - return (long)results.First().Id; - } + /// + public override async Task InsertAndGetIdAsync(T data, ValuePriority createdAt, CancellationToken cancellationToken) + { + var sql = this.CreateInsertAndGetIdSql(createdAt); + var command = new CommandDefinition(sql, data, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); + var reader = await this.Connection.QueryMultipleAsync(command).ConfigureAwait(false); + var results = await reader.ReadAsync().ConfigureAwait(false); + return (long)results.First().Id; + } - /// - /// - /// - /// - /// - /// - private string CreateInsertAndGetIdSql(ValuePriority createdAtPriority) + /// + /// + /// + /// + /// + /// + private string CreateInsertAndGetIdSql(ValuePriority createdAtPriority) + { + using (var builder = new QueryBuilder(this.DbProvider)) { - using (var builder = new QueryBuilder(this.DbProvider)) - { - builder.Insert(createdAtPriority); - builder.AppendLine(';'); - builder.Append("select last_insert_id() as Id;"); - var query = builder.Build(); - return query.Statement; - } + builder.Insert(createdAtPriority); + builder.AppendLine(';'); + builder.Append("select last_insert_id() as Id;"); + var query = builder.Build(); + return query.Statement; } - #endregion + } + #endregion - #region InsertIgnore - /// - public override int InsertIgnore(T data, ValuePriority createdAt) - { - var sql = this.CreateInsertIgnoreSql(createdAt); - return this.Connection.Execute(sql, data, this.Transaction, this.Timeout); - } + #region InsertIgnore + /// + public override int InsertIgnore(T data, ValuePriority createdAt) + { + var sql = this.CreateInsertIgnoreSql(createdAt); + return this.Connection.Execute(sql, data, this.Transaction, this.Timeout); + } - /// - public override Task InsertIgnoreAsync(T data, ValuePriority createdAt, CancellationToken cancellationToken) - { - var sql = this.CreateInsertIgnoreSql(createdAt); - var command = new CommandDefinition(sql, data, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); - return this.Connection.ExecuteAsync(command); - } + /// + public override Task InsertIgnoreAsync(T data, ValuePriority createdAt, CancellationToken cancellationToken) + { + var sql = this.CreateInsertIgnoreSql(createdAt); + var command = new CommandDefinition(sql, data, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); + return this.Connection.ExecuteAsync(command); + } - /// - /// - /// - /// - /// - private string CreateInsertIgnoreSql(ValuePriority createdAt) - { - var query = QueryBuilder.Insert(this.DbProvider, createdAt); - return query.Statement.Replace("insert into", "insert ignore into"); - } - #endregion + /// + /// + /// + /// + /// + private string CreateInsertIgnoreSql(ValuePriority createdAt) + { + var query = QueryBuilder.Insert(this.DbProvider, createdAt); + return query.Statement.Replace("insert into", "insert ignore into"); + } + #endregion - #region InsertIgnoreMulti - /// - public override int InsertIgnoreMulti(IEnumerable data, ValuePriority createdAt) - { - var sql = this.CreateInsertIgnoreSql(createdAt); - return this.Connection.Execute(sql, data, this.Transaction, this.Timeout); - } + #region InsertIgnoreMulti + /// + public override int InsertIgnoreMulti(IEnumerable data, ValuePriority createdAt) + { + var sql = this.CreateInsertIgnoreSql(createdAt); + return this.Connection.Execute(sql, data, this.Transaction, this.Timeout); + } - /// - public override Task InsertIgnoreMultiAsync(IEnumerable data, ValuePriority createdAt, CancellationToken cancellationToken) - { - var sql = this.CreateInsertIgnoreSql(createdAt); - var command = new CommandDefinition(sql, data, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); - return this.Connection.ExecuteAsync(command); - } - #endregion + /// + public override Task InsertIgnoreMultiAsync(IEnumerable data, ValuePriority createdAt, CancellationToken cancellationToken) + { + var sql = this.CreateInsertIgnoreSql(createdAt); + var command = new CommandDefinition(sql, data, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); + return this.Connection.ExecuteAsync(command); } + #endregion } diff --git a/src/DeclarativeSql/DbOperations/SqlServerOperation.cs b/src/DeclarativeSql/DbOperations/SqlServerOperation.cs index 51f2177..452eaf0 100644 --- a/src/DeclarativeSql/DbOperations/SqlServerOperation.cs +++ b/src/DeclarativeSql/DbOperations/SqlServerOperation.cs @@ -9,213 +9,212 @@ using DeclarativeSql.Mapping; using DeclarativeSql.Sql; +namespace DeclarativeSql.DbOperations; -namespace DeclarativeSql.DbOperations + +/// +/// Provides SQL Server specific database operation. +/// +internal class SqlServerOperation : DbOperation { - /// - /// Provides SQL Server specific database operation. - /// - internal class SqlServerOperation : DbOperation + #region Constructors + /// + public SqlServerOperation(IDbConnection connection, IDbTransaction? transaction, DbProvider provider, int? timeout) + : base(connection, transaction, provider, timeout) + { } + #endregion + + + #region InsertAndGetId + /// + public override long InsertAndGetId(T data, ValuePriority createdAt) { - #region Constructors - /// - public SqlServerOperation(IDbConnection connection, IDbTransaction? transaction, DbProvider provider, int? timeout) - : base(connection, transaction, provider, timeout) - { } - #endregion + var sql = this.CreateInsertAndGetIdSql(createdAt); + var reader = this.Connection.QueryMultiple(sql, data, this.Transaction, this.Timeout); + return (long)reader.Read().First().Id; + } - #region InsertAndGetId - /// - public override long InsertAndGetId(T data, ValuePriority createdAt) - { - var sql = this.CreateInsertAndGetIdSql(createdAt); - var reader = this.Connection.QueryMultiple(sql, data, this.Transaction, this.Timeout); - return (long)reader.Read().First().Id; - } + /// + public override async Task InsertAndGetIdAsync(T data, ValuePriority createdAt, CancellationToken cancellationToken) + { + var sql = this.CreateInsertAndGetIdSql(createdAt); + var command = new CommandDefinition(sql, data, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); + var reader = await this.Connection.QueryMultipleAsync(command).ConfigureAwait(false); + var results = await reader.ReadAsync().ConfigureAwait(false); + return (long)results.First().Id; + } - /// - public override async Task InsertAndGetIdAsync(T data, ValuePriority createdAt, CancellationToken cancellationToken) + /// + /// + /// + /// + /// + /// + private string CreateInsertAndGetIdSql(ValuePriority createdAtPriority) + { + using (var builder = new QueryBuilder(this.DbProvider)) { - var sql = this.CreateInsertAndGetIdSql(createdAt); - var command = new CommandDefinition(sql, data, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); - var reader = await this.Connection.QueryMultipleAsync(command).ConfigureAwait(false); - var results = await reader.ReadAsync().ConfigureAwait(false); - return (long)results.First().Id; + builder.Insert(createdAtPriority); + builder.AppendLine(';'); + builder.Append("select cast(scope_identity() as bigint) as Id;"); + var query = builder.Build(); + return query.Statement; } + } + #endregion - /// - /// - /// - /// - /// - /// - private string CreateInsertAndGetIdSql(ValuePriority createdAtPriority) - { - using (var builder = new QueryBuilder(this.DbProvider)) - { - builder.Insert(createdAtPriority); - builder.AppendLine(';'); - builder.Append("select cast(scope_identity() as bigint) as Id;"); - var query = builder.Build(); - return query.Statement; - } - } - #endregion + #region InsertIgnore + /// + public override int InsertIgnore(T data, ValuePriority createdAt) + { + var sql = this.CreateInsertIgnoreSql(createdAt); + return this.Connection.Execute(sql, data, this.Transaction, this.Timeout); + } - #region InsertIgnore - /// - public override int InsertIgnore(T data, ValuePriority createdAt) - { - var sql = this.CreateInsertIgnoreSql(createdAt); - return this.Connection.Execute(sql, data, this.Transaction, this.Timeout); - } + /// + public override Task InsertIgnoreAsync(T data, ValuePriority createdAt, CancellationToken cancellationToken) + { + var sql = this.CreateInsertIgnoreSql(createdAt); + var command = new CommandDefinition(sql, data, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); + return this.Connection.ExecuteAsync(command); + } - /// - public override Task InsertIgnoreAsync(T data, ValuePriority createdAt, CancellationToken cancellationToken) + /// + /// + /// + /// + /// + /// + /// Create SQL like following: + /// + /// merge into [dbo].[Person] as T1 + /// using (select @Age as [Age], @Id as [Id], @Name as [Name]) as T2 + /// on (T1.[Age] = T2.[Age] and T1.[Name] = T2.[Name]) or (T1.[Id] = T2.[Id]) + /// when not matched then + /// insert ([Age], [Id], [Name], [CreatedAt], [ModifiedAt]) + /// values (@Age, @Id, @Name, @CreatedAt, @CreatedAt); + /// + private string CreateInsertIgnoreSql(ValuePriority createdAtPriority) + { + //--- 自動採番列以外に一意制約がない場合は通常の insert 文で OK + var table = TableInfo.Get(this.DbProvider.Database); + if (!table.Columns.Any(x => !x.IsAutoIncrement && x.IsUnique)) + return QueryBuilder.Insert(this.DbProvider, createdAtPriority).Statement; + + //--- 対象となる列 + var selectColumns + = table.Columns + .Where(x => !x.IsCreatedAt) + .Where(x => !x.IsModifiedAt) + .ToArray(); // システム定義 (CreatedAt / ModifiedAt) は特別扱いで外す + var uniqueColumnGroups = selectColumns.ToLookup(x => x.UniqueIndex); + var insertColumns = table.Columns.Where(x => !x.IsAutoIncrement).ToArray(); // 自動採番列は外す + + //--- 変数ショートカット + var bracket = this.DbProvider.KeywordBracket; + var prefix = this.DbProvider.BindParameterPrefix; + + //--- SQL 構築 + var builder = new StringBuilder(); + builder.Append("merge into "); + builder.Append(table.FullName); + builder.Append(" as T1"); + builder.Append("using (select "); + foreach (var x in selectColumns) { - var sql = this.CreateInsertIgnoreSql(createdAt); - var command = new CommandDefinition(sql, data, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); - return this.Connection.ExecuteAsync(command); + builder.Append(prefix); + builder.Append(x.MemberName); + builder.Append(" as "); + builder.Append(bracket.Begin); + builder.Append(x.ColumnName); + builder.Append(bracket.End); + builder.Append(", "); } - - - /// - /// - /// - /// - /// - /// - /// Create SQL like following: - /// - /// merge into [dbo].[Person] as T1 - /// using (select @Age as [Age], @Id as [Id], @Name as [Name]) as T2 - /// on (T1.[Age] = T2.[Age] and T1.[Name] = T2.[Name]) or (T1.[Id] = T2.[Id]) - /// when not matched then - /// insert ([Age], [Id], [Name], [CreatedAt], [ModifiedAt]) - /// values (@Age, @Id, @Name, @CreatedAt, @CreatedAt); - /// - private string CreateInsertIgnoreSql(ValuePriority createdAtPriority) + builder.Length -= 2; + builder.AppendLine(") as T2"); + foreach (var xs in uniqueColumnGroups.WithIndex()) { - //--- 自動採番列以外に一意制約がない場合は通常の insert 文で OK - var table = TableInfo.Get(this.DbProvider.Database); - if (!table.Columns.Any(x => !x.IsAutoIncrement && x.IsUnique)) - return QueryBuilder.Insert(this.DbProvider, createdAtPriority).Statement; - - //--- 対象となる列 - var selectColumns - = table.Columns - .Where(x => !x.IsCreatedAt) - .Where(x => !x.IsModifiedAt) - .ToArray(); // システム定義 (CreatedAt / ModifiedAt) は特別扱いで外す - var uniqueColumnGroups = selectColumns.ToLookup(x => x.UniqueIndex); - var insertColumns = table.Columns.Where(x => !x.IsAutoIncrement).ToArray(); // 自動採番列は外す - - //--- 変数ショートカット - var bracket = this.DbProvider.KeywordBracket; - var prefix = this.DbProvider.BindParameterPrefix; - - //--- SQL 構築 - var builder = new StringBuilder(); - builder.Append("merge into "); - builder.Append(table.FullName); - builder.Append(" as T1"); - builder.Append("using (select "); - foreach (var x in selectColumns) + builder.Append(xs.index == 0 ? " on " : " or "); + builder.Append('('); + foreach (var x in xs.element.WithIndex()) { - builder.Append(prefix); - builder.Append(x.MemberName); - builder.Append(" as "); + if (x.index > 0) + builder.Append(" and "); + + builder.Append("T1."); builder.Append(bracket.Begin); - builder.Append(x.ColumnName); + builder.Append(x.element.ColumnName); + builder.Append(bracket.End); + builder.Append(" = T2."); + builder.Append(bracket.Begin); + builder.Append(x.element.ColumnName); builder.Append(bracket.End); - builder.Append(", "); } - builder.Length -= 2; - builder.AppendLine(") as T2"); - foreach (var xs in uniqueColumnGroups.WithIndex()) + builder.Append(')'); + } + builder.AppendLine(); + builder.AppendLine("when not matched then"); + builder.Append(" insert ("); + foreach (var x in insertColumns) + { + builder.Append(bracket.Begin); + builder.Append(x.ColumnName); + builder.Append(bracket.End); + builder.Append(", "); + } + builder.Length -= 2; + builder.AppendLine(")"); + builder.Append(" values ("); + foreach (var x in insertColumns) + { + if (createdAtPriority == ValuePriority.Default) { - builder.Append(xs.index == 0 ? " on " : " or "); - builder.Append('('); - foreach (var x in xs.element.WithIndex()) + if (x.IsCreatedAt && x.DefaultValue is not null) { - if (x.index > 0) - builder.Append(" and "); - - builder.Append("T1."); - builder.Append(bracket.Begin); - builder.Append(x.element.ColumnName); - builder.Append(bracket.End); - builder.Append(" = T2."); - builder.Append(bracket.Begin); - builder.Append(x.element.ColumnName); - builder.Append(bracket.End); + builder.Append(x.DefaultValue); + builder.Append(", "); + continue; } - builder.Append(')'); - } - builder.AppendLine(); - builder.AppendLine("when not matched then"); - builder.Append(" insert ("); - foreach (var x in insertColumns) - { - builder.Append(bracket.Begin); - builder.Append(x.ColumnName); - builder.Append(bracket.End); - builder.Append(", "); - } - builder.Length -= 2; - builder.AppendLine(")"); - builder.Append(" values ("); - foreach (var x in insertColumns) - { - if (createdAtPriority == ValuePriority.Default) + if (x.IsModifiedAt && x.DefaultValue is not null) { - if (x.IsCreatedAt && x.DefaultValue is not null) - { - builder.Append(x.DefaultValue); - builder.Append(", "); - continue; - } - if (x.IsModifiedAt && x.DefaultValue is not null) - { - builder.Append(x.DefaultValue); - builder.Append(", "); - continue; - } + builder.Append(x.DefaultValue); + builder.Append(", "); + continue; } - builder.Append(prefix); - builder.Append(x.MemberName); - builder.Append(", "); } - builder.Append(");"); - - //--- ok - return builder.ToString(); + builder.Append(prefix); + builder.Append(x.MemberName); + builder.Append(", "); } - #endregion + builder.Append(");"); + //--- ok + return builder.ToString(); + } + #endregion - #region InsertIgnoreMulti - /// - public override int InsertIgnoreMulti(IEnumerable data, ValuePriority createdAt) - { - var sql = this.CreateInsertIgnoreSql(createdAt); - return this.Connection.Execute(sql, data, this.Transaction, this.Timeout); - } + #region InsertIgnoreMulti + /// + public override int InsertIgnoreMulti(IEnumerable data, ValuePriority createdAt) + { + var sql = this.CreateInsertIgnoreSql(createdAt); + return this.Connection.Execute(sql, data, this.Transaction, this.Timeout); + } - /// - public override Task InsertIgnoreMultiAsync(IEnumerable data, ValuePriority createdAt, CancellationToken cancellationToken) - { - var sql = this.CreateInsertIgnoreSql(createdAt); - var command = new CommandDefinition(sql, data, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); - return this.Connection.ExecuteAsync(command); - } - #endregion + + /// + public override Task InsertIgnoreMultiAsync(IEnumerable data, ValuePriority createdAt, CancellationToken cancellationToken) + { + var sql = this.CreateInsertIgnoreSql(createdAt); + var command = new CommandDefinition(sql, data, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); + return this.Connection.ExecuteAsync(command); } + #endregion } diff --git a/src/DeclarativeSql/DbOperations/SqliteOperation.cs b/src/DeclarativeSql/DbOperations/SqliteOperation.cs index 6cef86f..7325a8b 100644 --- a/src/DeclarativeSql/DbOperations/SqliteOperation.cs +++ b/src/DeclarativeSql/DbOperations/SqliteOperation.cs @@ -5,61 +5,60 @@ using Dapper; using DeclarativeSql.Sql; +namespace DeclarativeSql.DbOperations; -namespace DeclarativeSql.DbOperations + +/// +/// Provides SQLite specific database operation. +/// +internal class SqliteOperation : DbOperation { - /// - /// Provides SQLite specific database operation. - /// - internal class SqliteOperation : DbOperation - { - #region Constructors - /// - public SqliteOperation(IDbConnection connection, IDbTransaction? transaction, DbProvider provider, int? timeout) - : base(connection, transaction, provider, timeout) - { } - #endregion + #region Constructors + /// + public SqliteOperation(IDbConnection connection, IDbTransaction? transaction, DbProvider provider, int? timeout) + : base(connection, transaction, provider, timeout) + { } + #endregion - #region InsertAndGetId - /// - public override long InsertAndGetId(T data, ValuePriority createdAt) - { - var sql = this.CreateInsertAndGetIdSql(createdAt); - var reader = this.Connection.QueryMultiple(sql, data, this.Transaction, this.Timeout); - return (long)reader.Read().First().Id; - } + #region InsertAndGetId + /// + public override long InsertAndGetId(T data, ValuePriority createdAt) + { + var sql = this.CreateInsertAndGetIdSql(createdAt); + var reader = this.Connection.QueryMultiple(sql, data, this.Transaction, this.Timeout); + return (long)reader.Read().First().Id; + } - /// - public override async Task InsertAndGetIdAsync(T data, ValuePriority createdAt, CancellationToken cancellationToken) - { - var sql = this.CreateInsertAndGetIdSql(createdAt); - var command = new CommandDefinition(sql, data, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); - var reader = await this.Connection.QueryMultipleAsync(command).ConfigureAwait(false); - var results = await reader.ReadAsync().ConfigureAwait(false); - return (long)results.First().Id; - } + /// + public override async Task InsertAndGetIdAsync(T data, ValuePriority createdAt, CancellationToken cancellationToken) + { + var sql = this.CreateInsertAndGetIdSql(createdAt); + var command = new CommandDefinition(sql, data, this.Transaction, this.Timeout, null, CommandFlags.Buffered, cancellationToken); + var reader = await this.Connection.QueryMultipleAsync(command).ConfigureAwait(false); + var results = await reader.ReadAsync().ConfigureAwait(false); + return (long)results.First().Id; + } - /// - /// - /// - /// - /// - /// - private string CreateInsertAndGetIdSql(ValuePriority createdAtPriority) + /// + /// + /// + /// + /// + /// + private string CreateInsertAndGetIdSql(ValuePriority createdAtPriority) + { + using (var builder = new QueryBuilder(this.DbProvider)) { - using (var builder = new QueryBuilder(this.DbProvider)) - { - builder.Insert(createdAtPriority); - builder.AppendLine(';'); - builder.Append("select last_insert_rowid() as Id;"); - var query = builder.Build(); - return query.Statement; - } + builder.Insert(createdAtPriority); + builder.AppendLine(';'); + builder.Append("select last_insert_rowid() as Id;"); + var query = builder.Build(); + return query.Statement; } - #endregion } + #endregion } diff --git a/src/DeclarativeSql/DbProvider.cs b/src/DeclarativeSql/DbProvider.cs index aae2a96..9edbcab 100644 --- a/src/DeclarativeSql/DbProvider.cs +++ b/src/DeclarativeSql/DbProvider.cs @@ -2,147 +2,146 @@ using System.Linq; using DeclarativeSql.Sql; +namespace DeclarativeSql; -namespace DeclarativeSql + +/// +/// Provides database functions. +/// +public sealed class DbProvider { + #region Properties /// - /// Provides database functions. + /// Gets the database kind. /// - public sealed class DbProvider - { - #region Properties - /// - /// Gets the database kind. - /// - public DbKind Database { get; } + public DbKind Database { get; } - /// - /// Gets the default schema. - /// - public string? DefaultSchema { get; } + /// + /// Gets the default schema. + /// + public string? DefaultSchema { get; } - /// - /// Gets the bind parameter prefix. - /// - public char BindParameterPrefix { get; } + /// + /// Gets the bind parameter prefix. + /// + public char BindParameterPrefix { get; } - /// - /// Gets the SQL keyword bracket. - /// - public BracketPair KeywordBracket { get; } - #endregion + /// + /// Gets the SQL keyword bracket. + /// + public BracketPair KeywordBracket { get; } + #endregion - #region Constructors - /// - /// Creates instance. - /// - /// - /// - /// - /// - private DbProvider(DbKind database, string? defaultSchema, char bindParameterPrefix, in BracketPair keywordBracket) - { - this.Database = database; - this.DefaultSchema = defaultSchema; - this.BindParameterPrefix = bindParameterPrefix; - this.KeywordBracket = keywordBracket; - } + #region Constructors + /// + /// Creates instance. + /// + /// + /// + /// + /// + private DbProvider(DbKind database, string? defaultSchema, char bindParameterPrefix, in BracketPair keywordBracket) + { + this.Database = database; + this.DefaultSchema = defaultSchema; + this.BindParameterPrefix = bindParameterPrefix; + this.KeywordBracket = keywordBracket; + } - /// - /// Call when first access. - /// - static DbProvider() + /// + /// Call when first access. + /// + static DbProvider() + { + All = new[] { - All = new [] - { - SqlServer, - MySql, - Sqlite, - PostgreSql, - Oracle, - }; - ByDatabase = All.ToDictionary(x => x.Database); - } - #endregion - - - #region Instances - /// - /// Gets all database providers. - /// - public static IReadOnlyCollection All { get; } - - - /// - /// Gets all database providers by DbKind. - /// - public static IReadOnlyDictionary ByDatabase { get; } - - - /// - /// Gets the SQL Server provider. - /// - public static DbProvider SqlServer { get; } = new DbProvider - ( - DbKind.SqlServer, - "dbo", - '@', - new BracketPair('[', ']') - ); - - - /// - /// Gets the MySQL / Amazon Aurora / MariaDB provider. - /// - public static DbProvider MySql { get; } = new DbProvider - ( - DbKind.MySql, - null, - '@', - new BracketPair('`', '`') - ); - - - /// - /// Gets the SQLite provider. - /// - public static DbProvider Sqlite { get; } = new DbProvider - ( - DbKind.Sqlite, - null, - '@', - new BracketPair('"', '"') - ); - - - /// - /// Gets the PostgreSQL provider. - /// - public static DbProvider PostgreSql { get; } = new DbProvider - ( - DbKind.PostgreSql, - null, - ':', - new BracketPair('"', '"') - ); - - - /// - /// Gets the Oracle provider. - /// - public static DbProvider Oracle { get; } = new DbProvider - ( - DbKind.Oracle, - null, - ':', - new BracketPair('"', '"') - ); - #endregion + SqlServer, + MySql, + Sqlite, + PostgreSql, + Oracle, + }; + ByDatabase = All.ToDictionary(x => x.Database); } + #endregion + + + #region Instances + /// + /// Gets all database providers. + /// + public static IReadOnlyCollection All { get; } + + + /// + /// Gets all database providers by DbKind. + /// + public static IReadOnlyDictionary ByDatabase { get; } + + + /// + /// Gets the SQL Server provider. + /// + public static DbProvider SqlServer { get; } = new DbProvider + ( + DbKind.SqlServer, + "dbo", + '@', + new BracketPair('[', ']') + ); + + + /// + /// Gets the MySQL / Amazon Aurora / MariaDB provider. + /// + public static DbProvider MySql { get; } = new DbProvider + ( + DbKind.MySql, + null, + '@', + new BracketPair('`', '`') + ); + + + /// + /// Gets the SQLite provider. + /// + public static DbProvider Sqlite { get; } = new DbProvider + ( + DbKind.Sqlite, + null, + '@', + new BracketPair('"', '"') + ); + + + /// + /// Gets the PostgreSQL provider. + /// + public static DbProvider PostgreSql { get; } = new DbProvider + ( + DbKind.PostgreSql, + null, + ':', + new BracketPair('"', '"') + ); + + + /// + /// Gets the Oracle provider. + /// + public static DbProvider Oracle { get; } = new DbProvider + ( + DbKind.Oracle, + null, + ':', + new BracketPair('"', '"') + ); + #endregion } diff --git a/src/DeclarativeSql/HighAvailabilityConnection.cs b/src/DeclarativeSql/HighAvailabilityConnection.cs index bac98ab..e3c694e 100644 --- a/src/DeclarativeSql/HighAvailabilityConnection.cs +++ b/src/DeclarativeSql/HighAvailabilityConnection.cs @@ -1,179 +1,178 @@ using System; using System.Data; +namespace DeclarativeSql; -namespace DeclarativeSql + +/// +/// Provides a database connection with high availability. +/// +public abstract class HighAvailabilityConnection : IDisposable { + #region Properties /// - /// Provides a database connection with high availability. + /// Gets the connection string to the master DB. /// - public abstract class HighAvailabilityConnection : IDisposable - { - #region Properties - /// - /// Gets the connection string to the master DB. - /// - private string MasterConnectionString { get; } + private string MasterConnectionString { get; } - /// - /// Gets the connection string to the slave DB. - /// - private string SlaveConnectionString { get; } + /// + /// Gets the connection string to the slave DB. + /// + private string SlaveConnectionString { get; } - /// - /// Gets the connection to the master DB. - /// - public IDbConnection Master => this.GetConnection(ref this.master, this.MasterConnectionString, AvailabilityTarget.Master); - private IDbConnection? master = null; + /// + /// Gets the connection to the master DB. + /// + public IDbConnection Master => this.GetConnection(ref this.master, this.MasterConnectionString, AvailabilityTarget.Master); + private IDbConnection? master = null; - /// - /// Gets the connection to the slave DB. - /// - public IDbConnection Slave + /// + /// Gets the connection to the slave DB. + /// + public IDbConnection Slave + { + get { - get - { - if (this.ForceMaster) - return this.Master; + if (this.ForceMaster) + return this.Master; - if (this.MasterConnectionString == this.SlaveConnectionString) - return this.Master; + if (this.MasterConnectionString == this.SlaveConnectionString) + return this.Master; - return this.GetConnection(ref this.slave, this.SlaveConnectionString, AvailabilityTarget.Slave); - } + return this.GetConnection(ref this.slave, this.SlaveConnectionString, AvailabilityTarget.Slave); } - private IDbConnection? slave = null; + } + private IDbConnection? slave = null; - /// - /// Gets whether to use the master DB forcibly. - /// - private bool ForceMaster { get; } + /// + /// Gets whether to use the master DB forcibly. + /// + private bool ForceMaster { get; } - /// - /// Gets whether the resource has been released. - /// - private bool IsDisposed { get; set; } - #endregion + /// + /// Gets whether the resource has been released. + /// + private bool IsDisposed { get; set; } + #endregion - #region Constructors - /// - /// Creates instance. - /// - /// Connection string to the master DB. - /// Connection string to the slave DB. - /// Use the master DB forcibly. - public HighAvailabilityConnection(string masterConnectionString, string slaveConnectionString, bool forceMaster = false) - { - this.MasterConnectionString = masterConnectionString; - this.SlaveConnectionString = slaveConnectionString; - this.ForceMaster = forceMaster; - } + #region Constructors + /// + /// Creates instance. + /// + /// Connection string to the master DB. + /// Connection string to the slave DB. + /// Use the master DB forcibly. + public HighAvailabilityConnection(string masterConnectionString, string slaveConnectionString, bool forceMaster = false) + { + this.MasterConnectionString = masterConnectionString; + this.SlaveConnectionString = slaveConnectionString; + this.ForceMaster = forceMaster; + } - /// - /// Destroy instance. - /// - ~HighAvailabilityConnection() - => this.Dispose(false); - #endregion + /// + /// Destroy instance. + /// + ~HighAvailabilityConnection() + => this.Dispose(false); + #endregion - #region IDisposable Support - /// - /// Release used resources. - /// - public void Dispose() - { - this.Dispose(true); - GC.SuppressFinalize(this); - } + #region IDisposable Support + /// + /// Release used resources. + /// + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } - /// - /// Release used resources. - /// - /// - private void Dispose(bool _) - { - if (this.IsDisposed) - return; + /// + /// Release used resources. + /// + /// + private void Dispose(bool _) + { + if (this.IsDisposed) + return; - this.DisposeConnection(ref this.slave, AvailabilityTarget.Slave); - this.DisposeConnection(ref this.master, AvailabilityTarget.Master); - this.IsDisposed = true; - } - #endregion - - - #region abstract / virtual - /// - /// Creates a connection from the specified connection string. - /// - /// - /// - /// - protected abstract IDbConnection CreateConnection(string connectionString, AvailabilityTarget target); - - - /// - /// Called before the connection is opened. - /// - /// - protected virtual void OnOpen(AvailabilityTarget target){} - - - /// - /// Called when the connection is closed. - /// - /// - protected virtual void OnClose(AvailabilityTarget target){} - #endregion - - - #region Others - /// - /// Get a database connection. - /// - /// - /// - /// - /// - private ref IDbConnection GetConnection(ref IDbConnection? connection, string connectionString, AvailabilityTarget target) + this.DisposeConnection(ref this.slave, AvailabilityTarget.Slave); + this.DisposeConnection(ref this.master, AvailabilityTarget.Master); + this.IsDisposed = true; + } + #endregion + + + #region abstract / virtual + /// + /// Creates a connection from the specified connection string. + /// + /// + /// + /// + protected abstract IDbConnection CreateConnection(string connectionString, AvailabilityTarget target); + + + /// + /// Called before the connection is opened. + /// + /// + protected virtual void OnOpen(AvailabilityTarget target) { } + + + /// + /// Called when the connection is closed. + /// + /// + protected virtual void OnClose(AvailabilityTarget target) { } + #endregion + + + #region Others + /// + /// Get a database connection. + /// + /// + /// + /// + /// + private ref IDbConnection GetConnection(ref IDbConnection? connection, string connectionString, AvailabilityTarget target) + { + if (this.IsDisposed) + throw new ObjectDisposedException(target.ToString()); + + if (connection is null) { - if (this.IsDisposed) - throw new ObjectDisposedException(target.ToString()); - - if (connection is null) - { - this.OnOpen(AvailabilityTarget.Master); - connection = this.CreateConnection(connectionString, target); - connection.Open(); - } - return ref connection!; + this.OnOpen(AvailabilityTarget.Master); + connection = this.CreateConnection(connectionString, target); + connection.Open(); } + return ref connection!; + } - /// - /// Release the database connection. - /// - /// - /// - private void DisposeConnection(ref IDbConnection? connection, AvailabilityTarget target) - { - if (connection is null) - return; + /// + /// Release the database connection. + /// + /// + /// + private void DisposeConnection(ref IDbConnection? connection, AvailabilityTarget target) + { + if (connection is null) + return; - connection.Dispose(); - connection = null; - this.OnClose(target); - } - #endregion + connection.Dispose(); + connection = null; + this.OnClose(target); } + #endregion } diff --git a/src/DeclarativeSql/IDbConnectionExtensions.cs b/src/DeclarativeSql/IDbConnectionExtensions.cs index bac0ad7..8be6177 100644 --- a/src/DeclarativeSql/IDbConnectionExtensions.cs +++ b/src/DeclarativeSql/IDbConnectionExtensions.cs @@ -6,431 +6,430 @@ using System.Threading.Tasks; using DeclarativeSql.DbOperations; +namespace DeclarativeSql; -namespace DeclarativeSql + +/// +/// Provides extension methods. +/// +public static class IDbConnectionExtensions { + #region Count + /// + /// Gets the number of records in the specified table. + /// + /// + /// + /// + /// Record count + public static ulong Count(this IDbConnection connection, int? timeout = null) + => DbOperation.Create(connection, timeout).Count(); + + + /// + /// Gets the number of records that match the specified condition in the specified table. + /// + /// + /// + /// + /// + /// Record count + public static ulong Count(this IDbConnection connection, Expression> predicate, int? timeout = null) + => DbOperation.Create(connection, timeout).Count(predicate); + + + /// + /// Gets the number of records in the specified table. + /// + /// + /// + /// + /// + /// Record count + public static Task CountAsync(this IDbConnection connection, int? timeout = null, CancellationToken cancellationToken = default) + => DbOperation.Create(connection, timeout).CountAsync(cancellationToken); + + + /// + /// Gets the number of records that match the specified condition in the specified table. + /// + /// + /// + /// + /// + /// + /// Record count + public static Task CountAsync(this IDbConnection connection, Expression> predicate, int? timeout = null, CancellationToken cancellationToken = default) + => DbOperation.Create(connection, timeout).CountAsync(predicate, cancellationToken); + #endregion + + + #region Select + /// + /// Gets all records from the specified table. + /// + /// + /// + /// + /// + /// + public static List Select(this IDbConnection connection, Expression>? properties = null, int? timeout = null) + => DbOperation.Create(connection, timeout).Select(properties); + + + /// + /// Gets records that match the specified condition from the specified table. + /// + /// + /// + /// + /// + /// + /// + public static List Select(this IDbConnection connection, Expression> predicate, Expression>? properties = null, int? timeout = null) + => DbOperation.Create(connection, timeout).Select(predicate, properties); + + + /// + /// Gets all records from the specified table. + /// + /// + /// + /// + /// + /// + /// + public static Task> SelectAsync(this IDbConnection connection, Expression>? properties = null, int? timeout = null, CancellationToken cancellationToken = default) + => DbOperation.Create(connection, timeout).SelectAsync(properties, cancellationToken); + + + /// + /// Gets records that match the specified condition from the specified table. + /// + /// + /// + /// + /// + /// + /// + /// + public static Task> SelectAsync(this IDbConnection connection, Expression> predicate, Expression>? properties = null, int? timeout = null, CancellationToken cancellationToken = default) + => DbOperation.Create(connection, timeout).SelectAsync(predicate, properties, cancellationToken); + #endregion + + + #region Insert + /// + /// Inserts the specified data into the table. + /// + /// + /// + /// + /// + /// + /// Effected rows count + public static int Insert(this IDbConnection connection, T data, ValuePriority createdAt = default, int? timeout = null) + => DbOperation.Create(connection, timeout).Insert(data, createdAt); + + + /// + /// Inserts the specified data into the table. + /// + /// + /// + /// + /// + /// + /// + /// Effected rows count + public static Task InsertAsync(this IDbConnection connection, T data, ValuePriority createdAt = default, int? timeout = null, CancellationToken cancellationToken = default) + => DbOperation.Create(connection, timeout).InsertAsync(data, createdAt, cancellationToken); + #endregion + + + #region InsertMulti + /// + /// Inserts the specified data into the table. + /// + /// + /// + /// + /// + /// + /// Effected rows count + public static int InsertMulti(this IDbConnection connection, IEnumerable data, ValuePriority createdAt = default, int? timeout = null) + => DbOperation.Create(connection, timeout).InsertMulti(data, createdAt); + + + /// + /// Inserts the specified data into the table. + /// + /// + /// + /// + /// + /// + /// + /// Effected rows count + public static Task InsertMultiAsync(this IDbConnection connection, IEnumerable data, ValuePriority createdAt = default, int? timeout = null, CancellationToken cancellationToken = default) + => DbOperation.Create(connection, timeout).InsertMultiAsync(data, createdAt, cancellationToken); + #endregion + + + #region BulkInsert + /// + /// Inserts the specified data into the table using the bulk method. + /// + /// + /// + /// + /// + /// + /// Effected rows count + public static int BulkInsert(this IDbConnection connection, IEnumerable data, ValuePriority createdAt = default, int? timeout = null) + => DbOperation.Create(connection, timeout).BulkInsert(data, createdAt); + + + /// + /// Inserts the specified data into the table using the bulk method. + /// + /// + /// + /// + /// + /// + /// + /// Effected rows count + public static Task BulkInsertAsync(this IDbConnection connection, IEnumerable data, ValuePriority createdAt = default, int? timeout = null, CancellationToken cancellationToken = default) + => DbOperation.Create(connection, timeout).BulkInsertAsync(data, createdAt, cancellationToken); + #endregion + + + #region InsertAndGetId + /// + /// Inserts the specified data into the table and returns the automatically incremented ID. + /// + /// + /// + /// + /// + /// + /// Auto incremented ID + public static long InsertAndGetId(this IDbConnection connection, T data, ValuePriority createdAt = default, int? timeout = null) + => DbOperation.Create(connection, timeout).InsertAndGetId(data, createdAt); + + + /// + /// Inserts the specified data into the table and returns the automatically incremented ID. + /// + /// + /// + /// + /// + /// + /// + /// Auto incremented ID + public static Task InsertAndGetIdAsync(this IDbConnection connection, T data, ValuePriority createdAt = default, int? timeout = null, CancellationToken cancellationToken = default) + => DbOperation.Create(connection, timeout).InsertAndGetIdAsync(data, createdAt, cancellationToken); + #endregion + + + #region InsertIgnore + /// + /// Inserts the specified data into the table. + /// Insertion processing is not performed when there is a collision with a unique constraint. + /// + /// + /// + /// + /// + /// + /// Effected row count + public static int InsertIgnore(this IDbConnection connection, T data, ValuePriority createdAt = default, int? timeout = null) + => DbOperation.Create(connection, timeout).InsertIgnore(data, createdAt); + + + /// + /// Inserts the specified data into the table. + /// Insertion processing is not performed when there is a collision with a unique constraint. + /// + /// + /// + /// + /// + /// + /// + /// Effected row count + public static Task InsertIgnoreAsync(this IDbConnection connection, T data, ValuePriority createdAt = default, int? timeout = null, CancellationToken cancellationToken = default) + => DbOperation.Create(connection, timeout).InsertIgnoreAsync(data, createdAt, cancellationToken); + #endregion + + + #region InsertIgnoreMulti + /// + /// Inserts the specified data into the table. + /// Insertion processing is not performed when there is a collision with a unique constraint. + /// + /// + /// + /// + /// + /// + /// Effected row count + public static int InsertIgnoreMulti(this IDbConnection connection, IEnumerable data, ValuePriority createdAt = default, int? timeout = null) + => DbOperation.Create(connection, timeout).InsertIgnoreMulti(data, createdAt); + + + /// + /// Inserts the specified data into the table. + /// Insertion processing is not performed when there is a collision with a unique constraint. + /// + /// + /// + /// + /// + /// + /// + /// Effected row count + public static Task InsertIgnoreMultiAsync(this IDbConnection connection, IEnumerable data, ValuePriority createdAt = default, int? timeout = null, CancellationToken cancellationToken = default) + => DbOperation.Create(connection, timeout).InsertIgnoreMultiAsync(data, createdAt, cancellationToken); + #endregion + + + #region Update + /// + /// Updates records with the specified data. + /// + /// + /// + /// + /// + /// + /// + /// Effected rows count + public static int Update(this IDbConnection connection, T data, Expression>? properties = null, ValuePriority modifiedAt = default, int? timeout = null) + => DbOperation.Create(connection, timeout).Update(data, properties, modifiedAt); + + + /// + /// Updates records that match the specified conditions with the specified data. + /// + /// + /// + /// + /// + /// + /// + /// + /// Effected rows count + public static int Update(this IDbConnection connection, T data, Expression> predicate, Expression>? properties = null, ValuePriority modifiedAt = default, int? timeout = null) + => DbOperation.Create(connection, timeout).Update(data, predicate, properties, modifiedAt); + + + /// + /// Updates records with the specified data. + /// + /// + /// + /// + /// + /// + /// + /// + /// Effected rows count + public static Task UpdateAsync(this IDbConnection connection, T data, Expression>? properties = null, ValuePriority modifiedAt = default, int? timeout = null, CancellationToken cancellationToken = default) + => DbOperation.Create(connection, timeout).UpdateAsync(data, properties, modifiedAt, cancellationToken); + + + /// + /// Updates records that match the specified conditions with the specified data. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Effected rows count + public static Task UpdateAsync(this IDbConnection connection, T data, Expression> predicate, Expression>? properties = null, ValuePriority modifiedAt = default, int? timeout = null, CancellationToken cancellationToken = default) + => DbOperation.Create(connection, timeout).UpdateAsync(data, predicate, properties, modifiedAt, cancellationToken); + #endregion + + + #region Delete + /// + /// Deletes all records from the specified table. + /// + /// + /// + /// + /// Effected rows count + public static int Delete(this IDbConnection connection, int? timeout = null) + => DbOperation.Create(connection, timeout).Delete(); + + + /// + /// Deletes records that match the specified conditions from the specified table. + /// + /// + /// + /// + /// + /// Effected rows count + public static int Delete(this IDbConnection connection, Expression> predicate, int? timeout = null) + => DbOperation.Create(connection, timeout).Delete(predicate); + + + /// + /// Deletes all records from the specified table. + /// + /// + /// + /// + /// + /// Effected rows count + public static Task DeleteAsync(this IDbConnection connection, int? timeout = null, CancellationToken cancellationToken = default) + => DbOperation.Create(connection, timeout).DeleteAsync(cancellationToken); + + + /// + /// Deletes records that match the specified conditions from the specified table. + /// + /// + /// + /// + /// + /// + /// Effected rows count + public static Task DeleteAsync(this IDbConnection connection, Expression> predicate, int? timeout = null, CancellationToken cancellationToken = default) + => DbOperation.Create(connection, timeout).DeleteAsync(predicate, cancellationToken); + #endregion + + + #region Truncate + /// + /// Truncates the specified table. + /// + /// + /// + /// + /// -1 + public static int Truncate(this IDbConnection connection, int? timeout = null) + => DbOperation.Create(connection, timeout).Truncate(); + + /// - /// Provides extension methods. + /// Truncates the specified table. /// - public static class IDbConnectionExtensions - { - #region Count - /// - /// Gets the number of records in the specified table. - /// - /// - /// - /// - /// Record count - public static ulong Count(this IDbConnection connection, int? timeout = null) - => DbOperation.Create(connection, timeout).Count(); - - - /// - /// Gets the number of records that match the specified condition in the specified table. - /// - /// - /// - /// - /// - /// Record count - public static ulong Count(this IDbConnection connection, Expression> predicate, int? timeout = null) - => DbOperation.Create(connection, timeout).Count(predicate); - - - /// - /// Gets the number of records in the specified table. - /// - /// - /// - /// - /// - /// Record count - public static Task CountAsync(this IDbConnection connection, int? timeout = null, CancellationToken cancellationToken = default) - => DbOperation.Create(connection, timeout).CountAsync(cancellationToken); - - - /// - /// Gets the number of records that match the specified condition in the specified table. - /// - /// - /// - /// - /// - /// - /// Record count - public static Task CountAsync(this IDbConnection connection, Expression> predicate, int? timeout = null, CancellationToken cancellationToken = default) - => DbOperation.Create(connection, timeout).CountAsync(predicate, cancellationToken); - #endregion - - - #region Select - /// - /// Gets all records from the specified table. - /// - /// - /// - /// - /// - /// - public static List Select(this IDbConnection connection, Expression>? properties = null, int? timeout = null) - => DbOperation.Create(connection, timeout).Select(properties); - - - /// - /// Gets records that match the specified condition from the specified table. - /// - /// - /// - /// - /// - /// - /// - public static List Select(this IDbConnection connection, Expression> predicate, Expression>? properties = null, int? timeout = null) - => DbOperation.Create(connection, timeout).Select(predicate, properties); - - - /// - /// Gets all records from the specified table. - /// - /// - /// - /// - /// - /// - /// - public static Task> SelectAsync(this IDbConnection connection, Expression>? properties = null, int? timeout = null, CancellationToken cancellationToken = default) - => DbOperation.Create(connection, timeout).SelectAsync(properties, cancellationToken); - - - /// - /// Gets records that match the specified condition from the specified table. - /// - /// - /// - /// - /// - /// - /// - /// - public static Task> SelectAsync(this IDbConnection connection, Expression> predicate, Expression>? properties = null, int? timeout = null, CancellationToken cancellationToken = default) - => DbOperation.Create(connection, timeout).SelectAsync(predicate, properties, cancellationToken); - #endregion - - - #region Insert - /// - /// Inserts the specified data into the table. - /// - /// - /// - /// - /// - /// - /// Effected rows count - public static int Insert(this IDbConnection connection, T data, ValuePriority createdAt = default, int? timeout = null) - => DbOperation.Create(connection, timeout).Insert(data, createdAt); - - - /// - /// Inserts the specified data into the table. - /// - /// - /// - /// - /// - /// - /// - /// Effected rows count - public static Task InsertAsync(this IDbConnection connection, T data, ValuePriority createdAt = default, int? timeout = null, CancellationToken cancellationToken = default) - => DbOperation.Create(connection, timeout).InsertAsync(data, createdAt, cancellationToken); - #endregion - - - #region InsertMulti - /// - /// Inserts the specified data into the table. - /// - /// - /// - /// - /// - /// - /// Effected rows count - public static int InsertMulti(this IDbConnection connection, IEnumerable data, ValuePriority createdAt = default, int? timeout = null) - => DbOperation.Create(connection, timeout).InsertMulti(data, createdAt); - - - /// - /// Inserts the specified data into the table. - /// - /// - /// - /// - /// - /// - /// - /// Effected rows count - public static Task InsertMultiAsync(this IDbConnection connection, IEnumerable data, ValuePriority createdAt = default, int? timeout = null, CancellationToken cancellationToken = default) - => DbOperation.Create(connection, timeout).InsertMultiAsync(data, createdAt, cancellationToken); - #endregion - - - #region BulkInsert - /// - /// Inserts the specified data into the table using the bulk method. - /// - /// - /// - /// - /// - /// - /// Effected rows count - public static int BulkInsert(this IDbConnection connection, IEnumerable data, ValuePriority createdAt = default, int? timeout = null) - => DbOperation.Create(connection, timeout).BulkInsert(data, createdAt); - - - /// - /// Inserts the specified data into the table using the bulk method. - /// - /// - /// - /// - /// - /// - /// - /// Effected rows count - public static Task BulkInsertAsync(this IDbConnection connection, IEnumerable data, ValuePriority createdAt = default, int? timeout = null, CancellationToken cancellationToken = default) - => DbOperation.Create(connection, timeout).BulkInsertAsync(data, createdAt, cancellationToken); - #endregion - - - #region InsertAndGetId - /// - /// Inserts the specified data into the table and returns the automatically incremented ID. - /// - /// - /// - /// - /// - /// - /// Auto incremented ID - public static long InsertAndGetId(this IDbConnection connection, T data, ValuePriority createdAt = default, int? timeout = null) - => DbOperation.Create(connection, timeout).InsertAndGetId(data, createdAt); - - - /// - /// Inserts the specified data into the table and returns the automatically incremented ID. - /// - /// - /// - /// - /// - /// - /// - /// Auto incremented ID - public static Task InsertAndGetIdAsync(this IDbConnection connection, T data, ValuePriority createdAt = default, int? timeout = null, CancellationToken cancellationToken = default) - => DbOperation.Create(connection, timeout).InsertAndGetIdAsync(data, createdAt, cancellationToken); - #endregion - - - #region InsertIgnore - /// - /// Inserts the specified data into the table. - /// Insertion processing is not performed when there is a collision with a unique constraint. - /// - /// - /// - /// - /// - /// - /// Effected row count - public static int InsertIgnore(this IDbConnection connection, T data, ValuePriority createdAt = default, int? timeout = null) - => DbOperation.Create(connection, timeout).InsertIgnore(data, createdAt); - - - /// - /// Inserts the specified data into the table. - /// Insertion processing is not performed when there is a collision with a unique constraint. - /// - /// - /// - /// - /// - /// - /// - /// Effected row count - public static Task InsertIgnoreAsync(this IDbConnection connection, T data, ValuePriority createdAt = default, int? timeout = null, CancellationToken cancellationToken = default) - => DbOperation.Create(connection, timeout).InsertIgnoreAsync(data, createdAt, cancellationToken); - #endregion - - - #region InsertIgnoreMulti - /// - /// Inserts the specified data into the table. - /// Insertion processing is not performed when there is a collision with a unique constraint. - /// - /// - /// - /// - /// - /// - /// Effected row count - public static int InsertIgnoreMulti(this IDbConnection connection, IEnumerable data, ValuePriority createdAt = default, int? timeout = null) - => DbOperation.Create(connection, timeout).InsertIgnoreMulti(data, createdAt); - - - /// - /// Inserts the specified data into the table. - /// Insertion processing is not performed when there is a collision with a unique constraint. - /// - /// - /// - /// - /// - /// - /// - /// Effected row count - public static Task InsertIgnoreMultiAsync(this IDbConnection connection, IEnumerable data, ValuePriority createdAt = default, int? timeout = null, CancellationToken cancellationToken = default) - => DbOperation.Create(connection, timeout).InsertIgnoreMultiAsync(data, createdAt, cancellationToken); - #endregion - - - #region Update - /// - /// Updates records with the specified data. - /// - /// - /// - /// - /// - /// - /// - /// Effected rows count - public static int Update(this IDbConnection connection, T data, Expression>? properties = null, ValuePriority modifiedAt = default, int? timeout = null) - => DbOperation.Create(connection, timeout).Update(data, properties, modifiedAt); - - - /// - /// Updates records that match the specified conditions with the specified data. - /// - /// - /// - /// - /// - /// - /// - /// - /// Effected rows count - public static int Update(this IDbConnection connection, T data, Expression> predicate, Expression>? properties = null, ValuePriority modifiedAt = default, int? timeout = null) - => DbOperation.Create(connection, timeout).Update(data, predicate, properties, modifiedAt); - - - /// - /// Updates records with the specified data. - /// - /// - /// - /// - /// - /// - /// - /// - /// Effected rows count - public static Task UpdateAsync(this IDbConnection connection, T data, Expression>? properties = null, ValuePriority modifiedAt = default, int? timeout = null, CancellationToken cancellationToken = default) - => DbOperation.Create(connection, timeout).UpdateAsync(data, properties, modifiedAt, cancellationToken); - - - /// - /// Updates records that match the specified conditions with the specified data. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// Effected rows count - public static Task UpdateAsync(this IDbConnection connection, T data, Expression> predicate, Expression>? properties = null, ValuePriority modifiedAt = default, int? timeout = null, CancellationToken cancellationToken = default) - => DbOperation.Create(connection, timeout).UpdateAsync(data, predicate, properties, modifiedAt, cancellationToken); - #endregion - - - #region Delete - /// - /// Deletes all records from the specified table. - /// - /// - /// - /// - /// Effected rows count - public static int Delete(this IDbConnection connection, int? timeout = null) - => DbOperation.Create(connection, timeout).Delete(); - - - /// - /// Deletes records that match the specified conditions from the specified table. - /// - /// - /// - /// - /// - /// Effected rows count - public static int Delete(this IDbConnection connection, Expression> predicate, int? timeout = null) - => DbOperation.Create(connection, timeout).Delete(predicate); - - - /// - /// Deletes all records from the specified table. - /// - /// - /// - /// - /// - /// Effected rows count - public static Task DeleteAsync(this IDbConnection connection, int? timeout = null, CancellationToken cancellationToken = default) - => DbOperation.Create(connection, timeout).DeleteAsync(cancellationToken); - - - /// - /// Deletes records that match the specified conditions from the specified table. - /// - /// - /// - /// - /// - /// - /// Effected rows count - public static Task DeleteAsync(this IDbConnection connection, Expression> predicate, int? timeout = null, CancellationToken cancellationToken = default) - => DbOperation.Create(connection, timeout).DeleteAsync(predicate, cancellationToken); - #endregion - - - #region Truncate - /// - /// Truncates the specified table. - /// - /// - /// - /// - /// -1 - public static int Truncate(this IDbConnection connection, int? timeout = null) - => DbOperation.Create(connection, timeout).Truncate(); - - - /// - /// Truncates the specified table. - /// - /// - /// - /// - /// - /// -1 - public static Task TruncateAsync(this IDbConnection connection, int? timeout = null, CancellationToken cancellationToken = default) - => DbOperation.Create(connection, timeout).TruncateAsync(cancellationToken); - #endregion - } + /// + /// + /// + /// + /// -1 + public static Task TruncateAsync(this IDbConnection connection, int? timeout = null, CancellationToken cancellationToken = default) + => DbOperation.Create(connection, timeout).TruncateAsync(cancellationToken); + #endregion } diff --git a/src/DeclarativeSql/Internals/EnumerableExtensions.cs b/src/DeclarativeSql/Internals/EnumerableExtensions.cs index e04a57e..8f75497 100644 --- a/src/DeclarativeSql/Internals/EnumerableExtensions.cs +++ b/src/DeclarativeSql/Internals/EnumerableExtensions.cs @@ -2,120 +2,119 @@ using System.Collections.Generic; using System.Linq; +namespace DeclarativeSql.Internals; -namespace DeclarativeSql.Internals + +/// +/// Provides extension methods +/// +internal static partial class EnumerableExtensions { + #region WithIndex + /// + /// Add an index to the element. + /// + /// + /// + /// + public static IEnumerable<(T element, int index)> WithIndex(this IEnumerable source) + => source.Select((x, i) => (x, i)); + #endregion + + + #region Materialize /// - /// Provides extension methods + /// Gets collection count if is materialized, otherwise null. /// - internal static partial class EnumerableExtensions + /// + /// + /// + public static int? CountIfMaterialized(this IEnumerable source) { - #region WithIndex - /// - /// Add an index to the element. - /// - /// - /// - /// - public static IEnumerable<(T element, int index)> WithIndex(this IEnumerable source) - => source.Select((x, i) => (x, i)); - #endregion - - - #region Materialize - /// - /// Gets collection count if is materialized, otherwise null. - /// - /// - /// - /// - public static int? CountIfMaterialized(this IEnumerable source) - { - if (source == Enumerable.Empty()) return 0; - if (source == Array.Empty()) return 0; - if (source is ICollection a) return a.Count; - if (source is IReadOnlyCollection b) return b.Count; + if (source == Enumerable.Empty()) return 0; + if (source == Array.Empty()) return 0; + if (source is ICollection a) return a.Count; + if (source is IReadOnlyCollection b) return b.Count; - return null; - } + return null; + } - /// - /// Gets collection if is materialized, otherwise ToArray();ed collection. - /// - /// - /// - /// - public static IEnumerable Materialize(this IEnumerable source, bool nullToEmpty = true) - { - if (source is null) - { - if (nullToEmpty) - return Enumerable.Empty(); - throw new ArgumentNullException(nameof(source)); - } - if (source is ICollection) return source; - if (source is IReadOnlyCollection) return source; - return source.ToArray(); - } - #endregion - - - #region Buffer - /// - /// Generates a sequence of non-overlapping adjacent buffers over the source sequence. - /// - /// Source sequence element type. - /// Source sequence. - /// Number of elements for allocated buffers. - /// Sequence of buffers containing source sequence elements. - public static IEnumerable> Buffer(this IEnumerable source, int count) + /// + /// Gets collection if is materialized, otherwise ToArray();ed collection. + /// + /// + /// + /// + public static IEnumerable Materialize(this IEnumerable source, bool nullToEmpty = true) + { + if (source is null) { - if (count <= 0) - throw new ArgumentOutOfRangeException(nameof(count)); - return BufferCore(source, count, count); + if (nullToEmpty) + return Enumerable.Empty(); + throw new ArgumentNullException(nameof(source)); } + if (source is ICollection) return source; + if (source is IReadOnlyCollection) return source; + return source.ToArray(); + } + #endregion - /// - /// Generates a sequence of buffers over the source sequence, with specified length and possible overlap. - /// - /// Source sequence element type. - /// Source sequence. - /// Number of elements for allocated buffers. - /// Number of elements to skip between the start of consecutive buffers. - /// Sequence of buffers containing source sequence elements. - public static IEnumerable> Buffer(this IEnumerable source, int count, int skip) - { - if (count <= 0) throw new ArgumentOutOfRangeException(nameof(count)); - if (skip <= 0) throw new ArgumentOutOfRangeException(nameof(skip)); - return BufferCore(source, count, skip); - } + #region Buffer + /// + /// Generates a sequence of non-overlapping adjacent buffers over the source sequence. + /// + /// Source sequence element type. + /// Source sequence. + /// Number of elements for allocated buffers. + /// Sequence of buffers containing source sequence elements. + public static IEnumerable> Buffer(this IEnumerable source, int count) + { + if (count <= 0) + throw new ArgumentOutOfRangeException(nameof(count)); + return BufferCore(source, count, count); + } - private static IEnumerable> BufferCore(IEnumerable source, int count, int skip) - { - var buffers = new Queue>(); + /// + /// Generates a sequence of buffers over the source sequence, with specified length and possible overlap. + /// + /// Source sequence element type. + /// Source sequence. + /// Number of elements for allocated buffers. + /// Number of elements to skip between the start of consecutive buffers. + /// Sequence of buffers containing source sequence elements. + public static IEnumerable> Buffer(this IEnumerable source, int count, int skip) + { + if (count <= 0) throw new ArgumentOutOfRangeException(nameof(count)); + if (skip <= 0) throw new ArgumentOutOfRangeException(nameof(skip)); + return BufferCore(source, count, skip); + } - var i = 0; - foreach (var item in source) - { - if (i % skip == 0) - buffers.Enqueue(new List(count)); - foreach (var buffer in buffers) - buffer.Add(item); + private static IEnumerable> BufferCore(IEnumerable source, int count, int skip) + { + var buffers = new Queue>(); - if (buffers.Count > 0 && buffers.Peek().Count == count) - yield return buffers.Dequeue(); + var i = 0; + foreach (var item in source) + { + if (i % skip == 0) + buffers.Enqueue(new List(count)); - i++; - } + foreach (var buffer in buffers) + buffer.Add(item); - while (buffers.Count > 0) + if (buffers.Count > 0 && buffers.Peek().Count == count) yield return buffers.Dequeue(); + + i++; } - #endregion + + while (buffers.Count > 0) + yield return buffers.Dequeue(); } + #endregion } diff --git a/src/DeclarativeSql/Internals/EnumerableExtensions_ToFrozenDictionary.cs b/src/DeclarativeSql/Internals/EnumerableExtensions_ToFrozenDictionary.cs index 17bb7b3..953accf 100644 --- a/src/DeclarativeSql/Internals/EnumerableExtensions_ToFrozenDictionary.cs +++ b/src/DeclarativeSql/Internals/EnumerableExtensions_ToFrozenDictionary.cs @@ -4,274 +4,273 @@ using System; using System.Collections.Generic; +namespace DeclarativeSql.Internals; -namespace DeclarativeSql.Internals + +/// +/// Provides extension methods. +/// +internal static partial class EnumerableExtensions { + #region FrozenDictionary + /// + /// Converts to . + /// + /// + /// + /// + /// + /// + public static FrozenDictionary ToFrozenDictionary(this IEnumerable source, Func keySelector) + => FrozenDictionary.Create(source, keySelector); + + + /// + /// Converts to . + /// + /// + /// + /// + /// + /// + /// + /// + public static FrozenDictionary ToFrozenDictionary(this IEnumerable source, Func keySelector, Func valueSelector) + => FrozenDictionary.Create(source, keySelector, valueSelector); + #endregion + + + #region String Specialized FrozenDictionary + /// + /// Converts to . + /// + /// + /// + /// + /// + public static FrozenStringKeyDictionary ToFrozenStringKeyDictionary(this IEnumerable source, Func keySelector) + => FrozenStringKeyDictionary.Create(source, keySelector); + + + /// + /// Converts to . + /// + /// + /// + /// + /// + /// + /// + public static FrozenStringKeyDictionary ToFrozenStringKeyDictionary(this IEnumerable source, Func keySelector, Func valueSelector) + => FrozenStringKeyDictionary.Create(source, keySelector, valueSelector); + #endregion + + + #region SByte Specialized FrozenDictionary + /// + /// Converts to . + /// + /// + /// + /// + /// + public static FrozenSByteKeyDictionary ToFrozenSByteKeyDictionary(this IEnumerable source, Func keySelector) + => FrozenSByteKeyDictionary.Create(source, keySelector); + + + /// + /// Converts to . + /// + /// + /// + /// + /// + /// + /// + public static FrozenSByteKeyDictionary ToFrozenSByteKeyDictionary(this IEnumerable source, Func keySelector, Func valueSelector) + => FrozenSByteKeyDictionary.Create(source, keySelector, valueSelector); + #endregion + + + #region Byte Specialized FrozenDictionary + /// + /// Converts to . + /// + /// + /// + /// + /// + public static FrozenByteKeyDictionary ToFrozenByteKeyDictionary(this IEnumerable source, Func keySelector) + => FrozenByteKeyDictionary.Create(source, keySelector); + + + /// + /// Converts to . + /// + /// + /// + /// + /// + /// + /// + public static FrozenByteKeyDictionary ToFrozenByteKeyDictionary(this IEnumerable source, Func keySelector, Func valueSelector) + => FrozenByteKeyDictionary.Create(source, keySelector, valueSelector); + #endregion + + + #region Int16 Specialized FrozenDictionary + /// + /// Converts to . + /// + /// + /// + /// + /// + public static FrozenInt16KeyDictionary ToFrozenInt16KeyDictionary(this IEnumerable source, Func keySelector) + => FrozenInt16KeyDictionary.Create(source, keySelector); + + + /// + /// Converts to . + /// + /// + /// + /// + /// + /// + /// + public static FrozenInt16KeyDictionary ToFrozenInt16KeyDictionary(this IEnumerable source, Func keySelector, Func valueSelector) + => FrozenInt16KeyDictionary.Create(source, keySelector, valueSelector); + #endregion + + + #region UInt16 Specialized FrozenDictionary + /// + /// Converts to . + /// + /// + /// + /// + /// + public static FrozenUInt16KeyDictionary ToFrozenUInt16KeyDictionary(this IEnumerable source, Func keySelector) + => FrozenUInt16KeyDictionary.Create(source, keySelector); + + + /// + /// Converts to . + /// + /// + /// + /// + /// + /// + /// + public static FrozenUInt16KeyDictionary ToFrozenUInt16KeyDictionary(this IEnumerable source, Func keySelector, Func valueSelector) + => FrozenUInt16KeyDictionary.Create(source, keySelector, valueSelector); + #endregion + + + #region Int32 Specialized FrozenDictionary + /// + /// Converts to . + /// + /// + /// + /// + /// + public static FrozenInt32KeyDictionary ToFrozenInt32KeyDictionary(this IEnumerable source, Func keySelector) + => FrozenInt32KeyDictionary.Create(source, keySelector); + + + /// + /// Converts to . + /// + /// + /// + /// + /// + /// + /// + public static FrozenInt32KeyDictionary ToFrozenInt32KeyDictionary(this IEnumerable source, Func keySelector, Func valueSelector) + => FrozenInt32KeyDictionary.Create(source, keySelector, valueSelector); + #endregion + + + #region UInt32 Specialized FrozenDictionary + /// + /// Converts to . + /// + /// + /// + /// + /// + public static FrozenUInt32KeyDictionary ToFrozenUInt32KeyDictionary(this IEnumerable source, Func keySelector) + => FrozenUInt32KeyDictionary.Create(source, keySelector); + + + /// + /// Converts to . + /// + /// + /// + /// + /// + /// + /// + public static FrozenUInt32KeyDictionary ToFrozenUInt32KeyDictionary(this IEnumerable source, Func keySelector, Func valueSelector) + => FrozenUInt32KeyDictionary.Create(source, keySelector, valueSelector); + #endregion + + + #region Int64 Specialized FrozenDictionary + /// + /// Converts to . + /// + /// + /// + /// + /// + public static FrozenInt64KeyDictionary ToFrozenInt64KeyDictionary(this IEnumerable source, Func keySelector) + => FrozenInt64KeyDictionary.Create(source, keySelector); + + + /// + /// Converts to . + /// + /// + /// + /// + /// + /// + /// + public static FrozenInt64KeyDictionary ToFrozenInt64KeyDictionary(this IEnumerable source, Func keySelector, Func valueSelector) + => FrozenInt64KeyDictionary.Create(source, keySelector, valueSelector); + #endregion + + + #region UInt64 Specialized FrozenDictionary + /// + /// Converts to . + /// + /// + /// + /// + /// + public static FrozenUInt64KeyDictionary ToFrozenUInt64KeyDictionary(this IEnumerable source, Func keySelector) + => FrozenUInt64KeyDictionary.Create(source, keySelector); + + /// - /// Provides extension methods. + /// Converts to . /// - internal static partial class EnumerableExtensions - { - #region FrozenDictionary - /// - /// Converts to . - /// - /// - /// - /// - /// - /// - public static FrozenDictionary ToFrozenDictionary(this IEnumerable source, Func keySelector) - => FrozenDictionary.Create(source, keySelector); - - - /// - /// Converts to . - /// - /// - /// - /// - /// - /// - /// - /// - public static FrozenDictionary ToFrozenDictionary(this IEnumerable source, Func keySelector, Func valueSelector) - => FrozenDictionary.Create(source, keySelector, valueSelector); - #endregion - - - #region String Specialized FrozenDictionary - /// - /// Converts to . - /// - /// - /// - /// - /// - public static FrozenStringKeyDictionary ToFrozenStringKeyDictionary(this IEnumerable source, Func keySelector) - => FrozenStringKeyDictionary.Create(source, keySelector); - - - /// - /// Converts to . - /// - /// - /// - /// - /// - /// - /// - public static FrozenStringKeyDictionary ToFrozenStringKeyDictionary(this IEnumerable source, Func keySelector, Func valueSelector) - => FrozenStringKeyDictionary.Create(source, keySelector, valueSelector); - #endregion - - - #region SByte Specialized FrozenDictionary - /// - /// Converts to . - /// - /// - /// - /// - /// - public static FrozenSByteKeyDictionary ToFrozenSByteKeyDictionary(this IEnumerable source, Func keySelector) - => FrozenSByteKeyDictionary.Create(source, keySelector); - - - /// - /// Converts to . - /// - /// - /// - /// - /// - /// - /// - public static FrozenSByteKeyDictionary ToFrozenSByteKeyDictionary(this IEnumerable source, Func keySelector, Func valueSelector) - => FrozenSByteKeyDictionary.Create(source, keySelector, valueSelector); - #endregion - - - #region Byte Specialized FrozenDictionary - /// - /// Converts to . - /// - /// - /// - /// - /// - public static FrozenByteKeyDictionary ToFrozenByteKeyDictionary(this IEnumerable source, Func keySelector) - => FrozenByteKeyDictionary.Create(source, keySelector); - - - /// - /// Converts to . - /// - /// - /// - /// - /// - /// - /// - public static FrozenByteKeyDictionary ToFrozenByteKeyDictionary(this IEnumerable source, Func keySelector, Func valueSelector) - => FrozenByteKeyDictionary.Create(source, keySelector, valueSelector); - #endregion - - - #region Int16 Specialized FrozenDictionary - /// - /// Converts to . - /// - /// - /// - /// - /// - public static FrozenInt16KeyDictionary ToFrozenInt16KeyDictionary(this IEnumerable source, Func keySelector) - => FrozenInt16KeyDictionary.Create(source, keySelector); - - - /// - /// Converts to . - /// - /// - /// - /// - /// - /// - /// - public static FrozenInt16KeyDictionary ToFrozenInt16KeyDictionary(this IEnumerable source, Func keySelector, Func valueSelector) - => FrozenInt16KeyDictionary.Create(source, keySelector, valueSelector); - #endregion - - - #region UInt16 Specialized FrozenDictionary - /// - /// Converts to . - /// - /// - /// - /// - /// - public static FrozenUInt16KeyDictionary ToFrozenUInt16KeyDictionary(this IEnumerable source, Func keySelector) - => FrozenUInt16KeyDictionary.Create(source, keySelector); - - - /// - /// Converts to . - /// - /// - /// - /// - /// - /// - /// - public static FrozenUInt16KeyDictionary ToFrozenUInt16KeyDictionary(this IEnumerable source, Func keySelector, Func valueSelector) - => FrozenUInt16KeyDictionary.Create(source, keySelector, valueSelector); - #endregion - - - #region Int32 Specialized FrozenDictionary - /// - /// Converts to . - /// - /// - /// - /// - /// - public static FrozenInt32KeyDictionary ToFrozenInt32KeyDictionary(this IEnumerable source, Func keySelector) - => FrozenInt32KeyDictionary.Create(source, keySelector); - - - /// - /// Converts to . - /// - /// - /// - /// - /// - /// - /// - public static FrozenInt32KeyDictionary ToFrozenInt32KeyDictionary(this IEnumerable source, Func keySelector, Func valueSelector) - => FrozenInt32KeyDictionary.Create(source, keySelector, valueSelector); - #endregion - - - #region UInt32 Specialized FrozenDictionary - /// - /// Converts to . - /// - /// - /// - /// - /// - public static FrozenUInt32KeyDictionary ToFrozenUInt32KeyDictionary(this IEnumerable source, Func keySelector) - => FrozenUInt32KeyDictionary.Create(source, keySelector); - - - /// - /// Converts to . - /// - /// - /// - /// - /// - /// - /// - public static FrozenUInt32KeyDictionary ToFrozenUInt32KeyDictionary(this IEnumerable source, Func keySelector, Func valueSelector) - => FrozenUInt32KeyDictionary.Create(source, keySelector, valueSelector); - #endregion - - - #region Int64 Specialized FrozenDictionary - /// - /// Converts to . - /// - /// - /// - /// - /// - public static FrozenInt64KeyDictionary ToFrozenInt64KeyDictionary(this IEnumerable source, Func keySelector) - => FrozenInt64KeyDictionary.Create(source, keySelector); - - - /// - /// Converts to . - /// - /// - /// - /// - /// - /// - /// - public static FrozenInt64KeyDictionary ToFrozenInt64KeyDictionary(this IEnumerable source, Func keySelector, Func valueSelector) - => FrozenInt64KeyDictionary.Create(source, keySelector, valueSelector); - #endregion - - - #region UInt64 Specialized FrozenDictionary - /// - /// Converts to . - /// - /// - /// - /// - /// - public static FrozenUInt64KeyDictionary ToFrozenUInt64KeyDictionary(this IEnumerable source, Func keySelector) - => FrozenUInt64KeyDictionary.Create(source, keySelector); - - - /// - /// Converts to . - /// - /// - /// - /// - /// - /// - /// - public static FrozenUInt64KeyDictionary ToFrozenUInt64KeyDictionary(this IEnumerable source, Func keySelector, Func valueSelector) - => FrozenUInt64KeyDictionary.Create(source, keySelector, valueSelector); - #endregion - } -} + /// + /// + /// + /// + /// + /// + public static FrozenUInt64KeyDictionary ToFrozenUInt64KeyDictionary(this IEnumerable source, Func keySelector, Func valueSelector) + => FrozenUInt64KeyDictionary.Create(source, keySelector, valueSelector); + #endregion +} \ No newline at end of file diff --git a/src/DeclarativeSql/Internals/EnumerableExtensions_ToFrozenDictionary.tt b/src/DeclarativeSql/Internals/EnumerableExtensions_ToFrozenDictionary.tt index c303430..046e02e 100644 --- a/src/DeclarativeSql/Internals/EnumerableExtensions_ToFrozenDictionary.tt +++ b/src/DeclarativeSql/Internals/EnumerableExtensions_ToFrozenDictionary.tt @@ -23,68 +23,67 @@ using System; using System.Collections.Generic; +namespace DeclarativeSql.Internals; -namespace DeclarativeSql.Internals + +/// +/// Provides extension methods. +/// +internal static partial class EnumerableExtensions { + #region FrozenDictionary /// - /// Provides extension methods. + /// Converts to . /// - internal static partial class EnumerableExtensions - { - #region FrozenDictionary - /// - /// Converts to . - /// - /// - /// - /// - /// - /// - public static FrozenDictionary ToFrozenDictionary(this IEnumerable source, Func keySelector) - => FrozenDictionary.Create(source, keySelector); + /// + /// + /// + /// + /// + public static FrozenDictionary ToFrozenDictionary(this IEnumerable source, Func keySelector) + => FrozenDictionary.Create(source, keySelector); - /// - /// Converts to . - /// - /// - /// - /// - /// - /// - /// - /// - public static FrozenDictionary ToFrozenDictionary(this IEnumerable source, Func keySelector, Func valueSelector) - => FrozenDictionary.Create(source, keySelector, valueSelector); - #endregion + /// + /// Converts to . + /// + /// + /// + /// + /// + /// + /// + /// + public static FrozenDictionary ToFrozenDictionary(this IEnumerable source, Func keySelector, Func valueSelector) + => FrozenDictionary.Create(source, keySelector, valueSelector); + #endregion <# foreach (var x in parameters) { #> - #region <#= x.TypeName #> Specialized FrozenDictionary - /// - /// Converts to . - /// - /// - /// - /// - /// - public static Frozen<#= x.TypeName #>KeyDictionary ToFrozen<#= x.TypeName #>KeyDictionary(this IEnumerable source, Func> keySelector) - => Frozen<#= x.TypeName #>KeyDictionary.Create(source, keySelector); + #region <#= x.TypeName #> Specialized FrozenDictionary + /// + /// Converts to . + /// + /// + /// + /// + /// + public static Frozen<#= x.TypeName #>KeyDictionary ToFrozen<#= x.TypeName #>KeyDictionary(this IEnumerable source, Func> keySelector) + => Frozen<#= x.TypeName #>KeyDictionary.Create(source, keySelector); - /// - /// Converts to . - /// - /// - /// - /// - /// - /// - /// - public static Frozen<#= x.TypeName #>KeyDictionary ToFrozen<#= x.TypeName #>KeyDictionary(this IEnumerable source, Func> keySelector, Func valueSelector) - => Frozen<#= x.TypeName #>KeyDictionary.Create(source, keySelector, valueSelector); - #endregion + /// + /// Converts to . + /// + /// + /// + /// + /// + /// + /// + public static Frozen<#= x.TypeName #>KeyDictionary ToFrozen<#= x.TypeName #>KeyDictionary(this IEnumerable source, Func> keySelector, Func valueSelector) + => Frozen<#= x.TypeName #>KeyDictionary.Create(source, keySelector, valueSelector); + #endregion <# } #> - } -} +} \ No newline at end of file diff --git a/src/DeclarativeSql/Internals/ExpressionHelper.cs b/src/DeclarativeSql/Internals/ExpressionHelper.cs index 63bfa17..6c3ba3b 100644 --- a/src/DeclarativeSql/Internals/ExpressionHelper.cs +++ b/src/DeclarativeSql/Internals/ExpressionHelper.cs @@ -2,108 +2,107 @@ using System.Collections.Generic; using System.Linq.Expressions; +namespace DeclarativeSql.Internals; -namespace DeclarativeSql.Internals + +/// +/// Provides helper functions for the expression. +/// +internal static class ExpressionHelper { /// - /// Provides helper functions for the expression. + /// Gets the member name from the expression tree. /// - internal static class ExpressionHelper + /// + /// + /// + public static string? GetMemberName(Expression> expression) { - /// - /// Gets the member name from the expression tree. - /// - /// - /// - /// - public static string? GetMemberName(Expression> expression) - { - var member = ExtractMemberExpression(expression); - return member?.Member.Name; - } + var member = ExtractMemberExpression(expression); + return member?.Member.Name; + } - /// - /// Gets the member name from the expression tree. - /// - /// - /// - /// - public static HashSet GetMemberNames(Expression> expression) + /// + /// Gets the member name from the expression tree. + /// + /// + /// + /// + public static HashSet GetMemberNames(Expression> expression) + { + var result = new HashSet(); + if (expression.Body is UnaryExpression unary) // for VB.NET { - var result = new HashSet(); - if (expression.Body is UnaryExpression unary) // for VB.NET + if (unary.NodeType == ExpressionType.Convert) // wrapped by convert expression { - if (unary.NodeType == ExpressionType.Convert) // wrapped by convert expression + if (unary.Operand is NewExpression @new) // x => new { x.Id, x.Name } { - if (unary.Operand is NewExpression @new) // x => new { x.Id, x.Name } - { - addMembers(result, @new); - } - else if (unary.Operand is MemberExpression member) // x => x.Id - { - result.Add(member.Member.Name); - } + addMembers(result, @new); + } + else if (unary.Operand is MemberExpression member) // x => x.Id + { + result.Add(member.Member.Name); } } - else if (expression.Body is NewExpression @new) // x => new { x.Id, x.Name } - { - addMembers(result, @new); - } - else // x => x.Id - { - var name = GetMemberName(expression); - if (name is not null) - result.Add(name); - } - return result; + } + else if (expression.Body is NewExpression @new) // x => new { x.Id, x.Name } + { + addMembers(result, @new); + } + else // x => x.Id + { + var name = GetMemberName(expression); + if (name is not null) + result.Add(name); + } + return result; - #region Local Functions - static void addMembers(HashSet buffer, NewExpression expression) - { - var members = expression.Members; - if (members is null) - return; + #region Local Functions + static void addMembers(HashSet buffer, NewExpression expression) + { + var members = expression.Members; + if (members is null) + return; - for (var i = 0; i < members.Count; i++) - { - var name = members[i].Name; - buffer.Add(name); - } + for (var i = 0; i < members.Count; i++) + { + var name = members[i].Name; + buffer.Add(name); } - #endregion } + #endregion + } - /// - /// Extracts the from the expression tree. - /// - /// - /// - public static MemberExpression? ExtractMemberExpression(LambdaExpression expression) - => ExtractMemberExpression(expression.Body); + /// + /// Extracts the from the expression tree. + /// + /// + /// + public static MemberExpression? ExtractMemberExpression(LambdaExpression expression) + => ExtractMemberExpression(expression.Body); - /// - /// Extracts the from the expression tree. - /// - /// - /// - public static MemberExpression? ExtractMemberExpression(Expression expression) - { - if (expression is MemberExpression member1) - return member1; + /// + /// Extracts the from the expression tree. + /// + /// + /// + public static MemberExpression? ExtractMemberExpression(Expression expression) + { + if (expression is MemberExpression member1) + return member1; - //--- for boxing - var unary = expression as UnaryExpression; - if (unary is not null) + //--- for boxing + var unary = expression as UnaryExpression; + if (unary is not null) if (unary.NodeType == ExpressionType.Convert) - if (unary.Operand is MemberExpression member2) - return member2; + if (unary.Operand is MemberExpression member2) + return member2; - return null; - } + return null; } } diff --git a/src/DeclarativeSql/Internals/FrozenDictionary.cs b/src/DeclarativeSql/Internals/FrozenDictionary.cs index a325d99..5d24663 100644 --- a/src/DeclarativeSql/Internals/FrozenDictionary.cs +++ b/src/DeclarativeSql/Internals/FrozenDictionary.cs @@ -6,3237 +6,3236 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; +namespace DeclarativeSql.Internals; -namespace DeclarativeSql.Internals + +/// +/// Provides a read-only dictionary that contents are fixed at the time of instance creation. +/// +/// The type of keys in the dictionary. +/// The type of values in the dictionary. +/// +/// Reference: +/// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs +/// +internal sealed class FrozenDictionary : IReadOnlyDictionary { + #region Constants + private static readonly Func PassThrough = x => x; + #endregion + + + #region Fields + private Entry[] buckets; + private int size; + private readonly float loadFactor; + #endregion + + + #region Constructors /// - /// Provides a read-only dictionary that contents are fixed at the time of instance creation. + /// Creates instance. /// - /// The type of keys in the dictionary. - /// The type of values in the dictionary. - /// - /// Reference: - /// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs - /// - internal sealed class FrozenDictionary : IReadOnlyDictionary + /// + /// + private FrozenDictionary(int bucketSize, float loadFactor) { - #region Constants - private static readonly Func PassThrough = x => x; - #endregion + this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; + this.loadFactor = loadFactor; + } + #endregion - #region Fields - private Entry[] buckets; - private int size; - private readonly float loadFactor; - #endregion + #region Create + /// + /// Creates a from an according to a specified key selector function. + /// + /// + /// + /// + public static FrozenDictionary Create(IEnumerable source, Func keySelector) + => Create(source, keySelector, PassThrough); - #region Constructors - /// - /// Creates instance. - /// - /// - /// - private FrozenDictionary(int bucketSize, float loadFactor) + /// + /// Creates a from an according to specified key selector and value selector functions. + /// + /// + /// + /// + /// + /// + public static FrozenDictionary Create(IEnumerable source, Func keySelector, Func valueSelector) + { + const int initialSize = 4; + const float loadFactor = 0.75f; + var size = source.CountIfMaterialized() ?? initialSize; + var bucketSize = CalculateCapacity(size, loadFactor); + var result = new FrozenDictionary(bucketSize, loadFactor); + + foreach (var x in source) { - this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; - this.loadFactor = loadFactor; + var key = keySelector(x); + var value = valueSelector(x); + if (!result.TryAddInternal(key, value, out _)) + throw new ArgumentException($"Key was already exists. Key:{key}"); } - #endregion + + return result; + } + #endregion - #region Create - /// - /// Creates a from an according to a specified key selector function. - /// - /// - /// - /// - public static FrozenDictionary Create(IEnumerable source, Func keySelector) - => Create(source, keySelector, PassThrough); - - - /// - /// Creates a from an according to specified key selector and value selector functions. - /// - /// - /// - /// - /// - /// - public static FrozenDictionary Create(IEnumerable source, Func keySelector, Func valueSelector) + #region Add + /// + /// Add element. + /// + /// + /// + /// + /// + private bool TryAddInternal(TKey key, TValue value, out TValue resultingValue) + { + var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); + if (this.buckets.Length < nextCapacity) { - const int initialSize = 4; - const float loadFactor = 0.75f; - var size = source.CountIfMaterialized() ?? initialSize; - var bucketSize = CalculateCapacity(size, loadFactor); - var result = new FrozenDictionary(bucketSize, loadFactor); - - foreach (var x in source) + //--- rehash + var nextBucket = new Entry[nextCapacity]; + for (int i = 0; i < this.buckets.Length; i++) { - var key = keySelector(x); - var value = valueSelector(x); - if (!result.TryAddInternal(key, value, out _)) - throw new ArgumentException($"Key was already exists. Key:{key}"); + var e = this.buckets[i]; + while (e is not null) + { + var newEntry = new Entry(e.Key, e.Value, e.Hash); + AddToBuckets(nextBucket, key, newEntry, default, out _); + e = e.Next; + } } - return result; + var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); + this.buckets = nextBucket; + if (success) + this.size++; + + return success; } - #endregion + else + { + var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); + if (success) + this.size++; + return success; + } - #region Add - /// - /// Add element. - /// - /// - /// - /// - /// - private bool TryAddInternal(TKey key, TValue value, out TValue resultingValue) + #region Local Functions + //--- please pass 'key + newEntry' or 'key + value'. + static bool AddToBuckets(Entry[] buckets, TKey newKey, Entry newEntry, TValue value, out TValue resultingValue) { - var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); - if (this.buckets.Length < nextCapacity) + var hash = newEntry?.Hash ?? EqualityComparer.Default.GetHashCode(newKey); + var index = hash & (buckets.Length - 1); + if (buckets[index] is null) { - //--- rehash - var nextBucket = new Entry[nextCapacity]; - for (int i = 0; i < this.buckets.Length; i++) + if (newEntry is null) { - var e = this.buckets[i]; - while (e is not null) - { - var newEntry = new Entry(e.Key, e.Value, e.Hash); - AddToBuckets(nextBucket, key, newEntry, default, out _); - e = e.Next; - } + resultingValue = value; + buckets[index] = new Entry(newKey, resultingValue, hash); + } + else + { + resultingValue = newEntry.Value; + buckets[index] = newEntry; } - - var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); - this.buckets = nextBucket; - if (success) - this.size++; - - return success; } else { - var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); - if (success) - this.size++; - - return success; - } - - #region Local Functions - //--- please pass 'key + newEntry' or 'key + value'. - static bool AddToBuckets(Entry[] buckets, TKey newKey, Entry newEntry, TValue value, out TValue resultingValue) - { - var hash = newEntry?.Hash ?? EqualityComparer.Default.GetHashCode(newKey); - var index = hash & (buckets.Length - 1); - if (buckets[index] is null) + var lastEntry = buckets[index]; + while (true) { - if (newEntry is null) - { - resultingValue = value; - buckets[index] = new Entry(newKey, resultingValue, hash); - } - else + if (EqualityComparer.Default.Equals(lastEntry.Key, newKey)) { - resultingValue = newEntry.Value; - buckets[index] = newEntry; + resultingValue = lastEntry.Value; + return false; } - } - else - { - var lastEntry = buckets[index]; - while (true) + + if (lastEntry.Next is null) { - if (EqualityComparer.Default.Equals(lastEntry.Key, newKey)) + if (newEntry is null) { - resultingValue = lastEntry.Value; - return false; + resultingValue = value; + lastEntry.Next = new Entry(newKey, resultingValue, hash); } - - if (lastEntry.Next is null) + else { - if (newEntry is null) - { - resultingValue = value; - lastEntry.Next = new Entry(newKey, resultingValue, hash); - } - else - { - resultingValue = newEntry.Value; - lastEntry.Next = newEntry; - } - break; + resultingValue = newEntry.Value; + lastEntry.Next = newEntry; } - - lastEntry = lastEntry.Next; + break; } + + lastEntry = lastEntry.Next; } - return true; } - #endregion + return true; } + #endregion + } - /// - /// Calculates bucket capacity. - /// - /// - /// - /// - private static int CalculateCapacity(int collectionSize, float loadFactor) - { - var initialCapacity = (int)(collectionSize / loadFactor); - var capacity = 1; - while (capacity < initialCapacity) - capacity <<= 1; + /// + /// Calculates bucket capacity. + /// + /// + /// + /// + private static int CalculateCapacity(int collectionSize, float loadFactor) + { + var initialCapacity = (int)(collectionSize / loadFactor); + var capacity = 1; + while (capacity < initialCapacity) + capacity <<= 1; - if (capacity < 8) - return 8; + if (capacity < 8) + return 8; - return capacity; - } - #endregion + return capacity; + } + #endregion - #region Get - /// - /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. - /// - /// - /// - /// - public TValue GetValueOrDefault(TKey key, TValue defaultValue = default) - => this.TryGetValue(key, out var value) - ? value - : defaultValue; - #endregion + #region Get + /// + /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. + /// + /// + /// + /// + public TValue GetValueOrDefault(TKey key, TValue defaultValue = default) + => this.TryGetValue(key, out var value) + ? value + : defaultValue; + #endregion + + + #region IReadOnlyDictionary implementations + /// + /// Gets the element that has the specified key in the read-only dictionary. + /// + /// The key to locate. + /// The element that has the specified key in the read-only dictionary. + public TValue this[TKey key] + => this.TryGetValue(key, out var value) + ? value + : throw new KeyNotFoundException(); - #region IReadOnlyDictionary implementations - /// - /// Gets the element that has the specified key in the read-only dictionary. - /// - /// The key to locate. - /// The element that has the specified key in the read-only dictionary. - public TValue this[TKey key] - => this.TryGetValue(key, out var value) - ? value - : throw new KeyNotFoundException(); - - - /// - /// Gets an enumerable collection that contains the keys in the read-only dictionary. - /// - public IEnumerable Keys - => throw new NotImplementedException(); - - - /// - /// Gets an enumerable collection that contains the values in the read-only dictionary. - /// - public IEnumerable Values - => throw new NotImplementedException(); - - - /// - /// Gets the number of elements in the collection. - /// - public int Count - => this.size; - - - /// - /// Determines whether the read-only dictionary contains an element that has the specified key. - /// - /// The key to locate. - /// - /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. - /// - public bool ContainsKey(TKey key) - => this.TryGetValue(key, out _); - - - /// - /// Gets the value that is associated with the specified key. - /// - /// The key to locate. - /// - /// When this method returns, the value associated with the specified key, if the key is found; - /// otherwise, the default value for the type of the value parameter. - /// This parameter is passed uninitialized. - /// - /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetValue(TKey key, out TValue value) + /// + /// Gets an enumerable collection that contains the keys in the read-only dictionary. + /// + public IEnumerable Keys + => throw new NotImplementedException(); + + + /// + /// Gets an enumerable collection that contains the values in the read-only dictionary. + /// + public IEnumerable Values + => throw new NotImplementedException(); + + + /// + /// Gets the number of elements in the collection. + /// + public int Count + => this.size; + + + /// + /// Determines whether the read-only dictionary contains an element that has the specified key. + /// + /// The key to locate. + /// + /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. + /// + public bool ContainsKey(TKey key) + => this.TryGetValue(key, out _); + + + /// + /// Gets the value that is associated with the specified key. + /// + /// The key to locate. + /// + /// When this method returns, the value associated with the specified key, if the key is found; + /// otherwise, the default value for the type of the value parameter. + /// This parameter is passed uninitialized. + /// + /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(TKey key, out TValue value) + { + var hash = EqualityComparer.Default.GetHashCode(key); + var index = hash & (this.buckets.Length - 1); + var next = this.buckets[index]; + while (next is not null) { - var hash = EqualityComparer.Default.GetHashCode(key); - var index = hash & (this.buckets.Length - 1); - var next = this.buckets[index]; - while (next is not null) + if (EqualityComparer.Default.Equals(next.Key, key)) { - if (EqualityComparer.Default.Equals(next.Key, key)) - { - value = next.Value; - return true; - } - next = next.Next; + value = next.Value; + return true; } - value = default; - return false; + next = next.Next; } + value = default; + return false; + } - /// - /// Returns an enumerator that iterates through the collection. - /// - /// An enumerator that can be used to iterate through the collection. - public IEnumerator> GetEnumerator() - => throw new NotImplementedException(); + /// + /// Returns an enumerator that iterates through the collection. + /// + /// An enumerator that can be used to iterate through the collection. + public IEnumerator> GetEnumerator() + => throw new NotImplementedException(); - /// - /// Returns an enumerator that iterates through a collection. - /// - /// An object that can be used to iterate through the collection. - IEnumerator IEnumerable.GetEnumerator() - => throw new NotImplementedException(); - #endregion + /// + /// Returns an enumerator that iterates through a collection. + /// + /// An object that can be used to iterate through the collection. + IEnumerator IEnumerable.GetEnumerator() + => throw new NotImplementedException(); + #endregion - #region Inner Classes - /// - /// Represents entry. - /// - private class Entry - { - public readonly TKey Key; - public readonly TValue Value; - public readonly int Hash; - public Entry Next; + #region Inner Classes + /// + /// Represents entry. + /// + private class Entry + { + public readonly TKey Key; + public readonly TValue Value; + public readonly int Hash; + public Entry Next; - public Entry(TKey key, TValue value, int hash) - { - this.Key = key; - this.Value = value; - this.Hash = hash; - } + public Entry(TKey key, TValue value, int hash) + { + this.Key = key; + this.Value = value; + this.Hash = hash; } - #endregion } + #endregion +} + + + +/// +/// Provides a read-only dictionary that contents are fixed at the time of instance creation. +/// +/// The type of values in the dictionary. +/// +/// Reference: +/// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs +/// +/// This class is string specialized . +/// +internal sealed class FrozenStringKeyDictionary : IReadOnlyDictionary +{ + #region Constants + private static readonly Func PassThrough = x => x; + #endregion + + #region Fields + private Entry[] buckets; + private int size; + private readonly float loadFactor; + #endregion + #region Constructors /// - /// Provides a read-only dictionary that contents are fixed at the time of instance creation. + /// Creates instance. /// - /// The type of values in the dictionary. - /// - /// Reference: - /// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs - /// - /// This class is string specialized . - /// - internal sealed class FrozenStringKeyDictionary : IReadOnlyDictionary + /// + /// + private FrozenStringKeyDictionary(int bucketSize, float loadFactor) { - #region Constants - private static readonly Func PassThrough = x => x; - #endregion + this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; + this.loadFactor = loadFactor; + } + #endregion - #region Fields - private Entry[] buckets; - private int size; - private readonly float loadFactor; - #endregion + #region Create + /// + /// Creates a from an according to a specified key selector function. + /// + /// + /// + /// + public static FrozenStringKeyDictionary Create(IEnumerable source, Func keySelector) + => Create(source, keySelector, PassThrough); + + /// + /// Creates a from an according to specified key selector and value selector functions. + /// + /// + /// + /// + /// + /// + public static FrozenStringKeyDictionary Create(IEnumerable source, Func keySelector, Func valueSelector) + { + const int initialSize = 4; + const float loadFactor = 0.75f; + var size = source.CountIfMaterialized() ?? initialSize; + var bucketSize = CalculateCapacity(size, loadFactor); + var result = new FrozenStringKeyDictionary(bucketSize, loadFactor); - #region Constructors - /// - /// Creates instance. - /// - /// - /// - private FrozenStringKeyDictionary(int bucketSize, float loadFactor) + foreach (var x in source) { - this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; - this.loadFactor = loadFactor; + var key = keySelector(x); + var value = valueSelector(x); + if (!result.TryAddInternal(key, value, out _)) + throw new ArgumentException($"Key was already exists. Key:{key}"); } - #endregion + return result; + } + #endregion - #region Create - /// - /// Creates a from an according to a specified key selector function. - /// - /// - /// - /// - public static FrozenStringKeyDictionary Create(IEnumerable source, Func keySelector) - => Create(source, keySelector, PassThrough); - - - /// - /// Creates a from an according to specified key selector and value selector functions. - /// - /// - /// - /// - /// - /// - public static FrozenStringKeyDictionary Create(IEnumerable source, Func keySelector, Func valueSelector) - { - const int initialSize = 4; - const float loadFactor = 0.75f; - var size = source.CountIfMaterialized() ?? initialSize; - var bucketSize = CalculateCapacity(size, loadFactor); - var result = new FrozenStringKeyDictionary(bucketSize, loadFactor); - foreach (var x in source) + #region Add + /// + /// Add element. + /// + /// + /// + /// + /// + private bool TryAddInternal(string key, TValue value, out TValue resultingValue) + { + var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); + if (this.buckets.Length < nextCapacity) + { + //--- rehash + var nextBucket = new Entry[nextCapacity]; + for (int i = 0; i < this.buckets.Length; i++) { - var key = keySelector(x); - var value = valueSelector(x); - if (!result.TryAddInternal(key, value, out _)) - throw new ArgumentException($"Key was already exists. Key:{key}"); + var e = this.buckets[i]; + while (e is not null) + { + var newEntry = new Entry(e.Key, e.Value, e.Hash); + AddToBuckets(nextBucket, key, newEntry, default, out _); + e = e.Next; + } } - return result; + var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); + this.buckets = nextBucket; + if (success) + this.size++; + + return success; } - #endregion + else + { + var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); + if (success) + this.size++; + return success; + } - #region Add - /// - /// Add element. - /// - /// - /// - /// - /// - private bool TryAddInternal(string key, TValue value, out TValue resultingValue) + #region Local Functions + //--- please pass 'key + newEntry' or 'key + value'. + static bool AddToBuckets(Entry[] buckets, string newKey, Entry newEntry, TValue value, out TValue resultingValue) { - var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); - if (this.buckets.Length < nextCapacity) + var hash = newEntry?.Hash ?? newKey.GetHashCode(); + var index = hash & (buckets.Length - 1); + if (buckets[index] is null) { - //--- rehash - var nextBucket = new Entry[nextCapacity]; - for (int i = 0; i < this.buckets.Length; i++) + if (newEntry is null) { - var e = this.buckets[i]; - while (e is not null) - { - var newEntry = new Entry(e.Key, e.Value, e.Hash); - AddToBuckets(nextBucket, key, newEntry, default, out _); - e = e.Next; - } + resultingValue = value; + buckets[index] = new Entry(newKey, resultingValue, hash); + } + else + { + resultingValue = newEntry.Value; + buckets[index] = newEntry; } - - var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); - this.buckets = nextBucket; - if (success) - this.size++; - - return success; } else { - var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); - if (success) - this.size++; - - return success; - } - - #region Local Functions - //--- please pass 'key + newEntry' or 'key + value'. - static bool AddToBuckets(Entry[] buckets, string newKey, Entry newEntry, TValue value, out TValue resultingValue) - { - var hash = newEntry?.Hash ?? newKey.GetHashCode(); - var index = hash & (buckets.Length - 1); - if (buckets[index] is null) + var lastEntry = buckets[index]; + while (true) { - if (newEntry is null) - { - resultingValue = value; - buckets[index] = new Entry(newKey, resultingValue, hash); - } - else + if (lastEntry.Key == newKey) { - resultingValue = newEntry.Value; - buckets[index] = newEntry; + resultingValue = lastEntry.Value; + return false; } - } - else - { - var lastEntry = buckets[index]; - while (true) + + if (lastEntry.Next is null) { - if (lastEntry.Key == newKey) + if (newEntry is null) { - resultingValue = lastEntry.Value; - return false; + resultingValue = value; + lastEntry.Next = new Entry(newKey, resultingValue, hash); } - - if (lastEntry.Next is null) + else { - if (newEntry is null) - { - resultingValue = value; - lastEntry.Next = new Entry(newKey, resultingValue, hash); - } - else - { - resultingValue = newEntry.Value; - lastEntry.Next = newEntry; - } - break; + resultingValue = newEntry.Value; + lastEntry.Next = newEntry; } - - lastEntry = lastEntry.Next; + break; } + + lastEntry = lastEntry.Next; } - return true; } - #endregion + return true; } + #endregion + } - /// - /// Calculates bucket capacity. - /// - /// - /// - /// - private static int CalculateCapacity(int collectionSize, float loadFactor) - { - var initialCapacity = (int)(collectionSize / loadFactor); - var capacity = 1; - while (capacity < initialCapacity) - capacity <<= 1; + /// + /// Calculates bucket capacity. + /// + /// + /// + /// + private static int CalculateCapacity(int collectionSize, float loadFactor) + { + var initialCapacity = (int)(collectionSize / loadFactor); + var capacity = 1; + while (capacity < initialCapacity) + capacity <<= 1; - if (capacity < 8) - return 8; + if (capacity < 8) + return 8; - return capacity; - } - #endregion + return capacity; + } + #endregion - #region Get - /// - /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. - /// - /// - /// - /// - public TValue GetValueOrDefault(string key, TValue defaultValue = default) - => this.TryGetValue(key, out var value) - ? value - : defaultValue; - #endregion + #region Get + /// + /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. + /// + /// + /// + /// + public TValue GetValueOrDefault(string key, TValue defaultValue = default) + => this.TryGetValue(key, out var value) + ? value + : defaultValue; + #endregion + + + #region IReadOnlyDictionary implementations + /// + /// Gets the element that has the specified key in the read-only dictionary. + /// + /// The key to locate. + /// The element that has the specified key in the read-only dictionary. + public TValue this[string key] + => this.TryGetValue(key, out var value) + ? value + : throw new KeyNotFoundException(); + + + /// + /// Gets an enumerable collection that contains the keys in the read-only dictionary. + /// + public IEnumerable Keys + => throw new NotImplementedException(); + + + /// + /// Gets an enumerable collection that contains the values in the read-only dictionary. + /// + public IEnumerable Values + => throw new NotImplementedException(); + + + /// + /// Gets the number of elements in the collection. + /// + public int Count + => this.size; + + + /// + /// Determines whether the read-only dictionary contains an element that has the specified key. + /// + /// The key to locate. + /// + /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. + /// + public bool ContainsKey(string key) + => this.TryGetValue(key, out _); - #region IReadOnlyDictionary implementations - /// - /// Gets the element that has the specified key in the read-only dictionary. - /// - /// The key to locate. - /// The element that has the specified key in the read-only dictionary. - public TValue this[string key] - => this.TryGetValue(key, out var value) - ? value - : throw new KeyNotFoundException(); - - - /// - /// Gets an enumerable collection that contains the keys in the read-only dictionary. - /// - public IEnumerable Keys - => throw new NotImplementedException(); - - - /// - /// Gets an enumerable collection that contains the values in the read-only dictionary. - /// - public IEnumerable Values - => throw new NotImplementedException(); - - - /// - /// Gets the number of elements in the collection. - /// - public int Count - => this.size; - - - /// - /// Determines whether the read-only dictionary contains an element that has the specified key. - /// - /// The key to locate. - /// - /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. - /// - public bool ContainsKey(string key) - => this.TryGetValue(key, out _); - - - /// - /// Gets the value that is associated with the specified key. - /// - /// The key to locate. - /// - /// When this method returns, the value associated with the specified key, if the key is found; - /// otherwise, the default value for the type of the value parameter. - /// This parameter is passed uninitialized. - /// - /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetValue(string key, out TValue value) + /// + /// Gets the value that is associated with the specified key. + /// + /// The key to locate. + /// + /// When this method returns, the value associated with the specified key, if the key is found; + /// otherwise, the default value for the type of the value parameter. + /// This parameter is passed uninitialized. + /// + /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(string key, out TValue value) + { + var hash = key.GetHashCode(); + var index = hash & (this.buckets.Length - 1); + var next = this.buckets[index]; + while (next is not null) { - var hash = key.GetHashCode(); - var index = hash & (this.buckets.Length - 1); - var next = this.buckets[index]; - while (next is not null) + if (next.Key == key) { - if (next.Key == key) - { - value = next.Value; - return true; - } - next = next.Next; + value = next.Value; + return true; } - value = default; - return false; + next = next.Next; } + value = default; + return false; + } - /// - /// Returns an enumerator that iterates through the collection. - /// - /// An enumerator that can be used to iterate through the collection. - public IEnumerator> GetEnumerator() - => throw new NotImplementedException(); + /// + /// Returns an enumerator that iterates through the collection. + /// + /// An enumerator that can be used to iterate through the collection. + public IEnumerator> GetEnumerator() + => throw new NotImplementedException(); - /// - /// Returns an enumerator that iterates through a collection. - /// - /// An object that can be used to iterate through the collection. - IEnumerator IEnumerable.GetEnumerator() - => throw new NotImplementedException(); - #endregion + /// + /// Returns an enumerator that iterates through a collection. + /// + /// An object that can be used to iterate through the collection. + IEnumerator IEnumerable.GetEnumerator() + => throw new NotImplementedException(); + #endregion - #region Inner Classes - /// - /// Represents entry. - /// - private class Entry - { - public readonly string Key; - public readonly TValue Value; - public readonly int Hash; - public Entry Next; + #region Inner Classes + /// + /// Represents entry. + /// + private class Entry + { + public readonly string Key; + public readonly TValue Value; + public readonly int Hash; + public Entry Next; - public Entry(string key, TValue value, int hash) - { - this.Key = key; - this.Value = value; - this.Hash = hash; - } + public Entry(string key, TValue value, int hash) + { + this.Key = key; + this.Value = value; + this.Hash = hash; } - #endregion } + #endregion +} + + + +/// +/// Provides a read-only dictionary that contents are fixed at the time of instance creation. +/// +/// The type of values in the dictionary. +/// +/// Reference: +/// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs +/// +/// This class is sbyte specialized . +/// +internal sealed class FrozenSByteKeyDictionary : IReadOnlyDictionary +{ + #region Constants + private static readonly Func PassThrough = x => x; + #endregion + #region Fields + private Entry[] buckets; + private int size; + private readonly float loadFactor; + #endregion + + #region Constructors /// - /// Provides a read-only dictionary that contents are fixed at the time of instance creation. + /// Creates instance. /// - /// The type of values in the dictionary. - /// - /// Reference: - /// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs - /// - /// This class is sbyte specialized . - /// - internal sealed class FrozenSByteKeyDictionary : IReadOnlyDictionary + /// + /// + private FrozenSByteKeyDictionary(int bucketSize, float loadFactor) { - #region Constants - private static readonly Func PassThrough = x => x; - #endregion + this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; + this.loadFactor = loadFactor; + } + #endregion - #region Fields - private Entry[] buckets; - private int size; - private readonly float loadFactor; - #endregion + #region Create + /// + /// Creates a from an according to a specified key selector function. + /// + /// + /// + /// + public static FrozenSByteKeyDictionary Create(IEnumerable source, Func keySelector) + => Create(source, keySelector, PassThrough); - #region Constructors - /// - /// Creates instance. - /// - /// - /// - private FrozenSByteKeyDictionary(int bucketSize, float loadFactor) + /// + /// Creates a from an according to specified key selector and value selector functions. + /// + /// + /// + /// + /// + /// + public static FrozenSByteKeyDictionary Create(IEnumerable source, Func keySelector, Func valueSelector) + { + const int initialSize = 4; + const float loadFactor = 0.75f; + var size = source.CountIfMaterialized() ?? initialSize; + var bucketSize = CalculateCapacity(size, loadFactor); + var result = new FrozenSByteKeyDictionary(bucketSize, loadFactor); + + foreach (var x in source) { - this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; - this.loadFactor = loadFactor; + var key = keySelector(x); + var value = valueSelector(x); + if (!result.TryAddInternal(key, value, out _)) + throw new ArgumentException($"Key was already exists. Key:{key}"); } - #endregion + return result; + } + #endregion - #region Create - /// - /// Creates a from an according to a specified key selector function. - /// - /// - /// - /// - public static FrozenSByteKeyDictionary Create(IEnumerable source, Func keySelector) - => Create(source, keySelector, PassThrough); - - - /// - /// Creates a from an according to specified key selector and value selector functions. - /// - /// - /// - /// - /// - /// - public static FrozenSByteKeyDictionary Create(IEnumerable source, Func keySelector, Func valueSelector) - { - const int initialSize = 4; - const float loadFactor = 0.75f; - var size = source.CountIfMaterialized() ?? initialSize; - var bucketSize = CalculateCapacity(size, loadFactor); - var result = new FrozenSByteKeyDictionary(bucketSize, loadFactor); - foreach (var x in source) + #region Add + /// + /// Add element. + /// + /// + /// + /// + /// + private bool TryAddInternal(sbyte key, TValue value, out TValue resultingValue) + { + var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); + if (this.buckets.Length < nextCapacity) + { + //--- rehash + var nextBucket = new Entry[nextCapacity]; + for (int i = 0; i < this.buckets.Length; i++) { - var key = keySelector(x); - var value = valueSelector(x); - if (!result.TryAddInternal(key, value, out _)) - throw new ArgumentException($"Key was already exists. Key:{key}"); + var e = this.buckets[i]; + while (e is not null) + { + var newEntry = new Entry(e.Key, e.Value, e.Hash); + AddToBuckets(nextBucket, key, newEntry, default, out _); + e = e.Next; + } } - return result; + var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); + this.buckets = nextBucket; + if (success) + this.size++; + + return success; } - #endregion + else + { + var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); + if (success) + this.size++; + return success; + } - #region Add - /// - /// Add element. - /// - /// - /// - /// - /// - private bool TryAddInternal(sbyte key, TValue value, out TValue resultingValue) + #region Local Functions + //--- please pass 'key + newEntry' or 'key + value'. + static bool AddToBuckets(Entry[] buckets, sbyte newKey, Entry newEntry, TValue value, out TValue resultingValue) { - var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); - if (this.buckets.Length < nextCapacity) + var hash = newEntry?.Hash ?? newKey.GetHashCode(); + var index = hash & (buckets.Length - 1); + if (buckets[index] is null) { - //--- rehash - var nextBucket = new Entry[nextCapacity]; - for (int i = 0; i < this.buckets.Length; i++) + if (newEntry is null) { - var e = this.buckets[i]; - while (e is not null) - { - var newEntry = new Entry(e.Key, e.Value, e.Hash); - AddToBuckets(nextBucket, key, newEntry, default, out _); - e = e.Next; - } + resultingValue = value; + buckets[index] = new Entry(newKey, resultingValue, hash); + } + else + { + resultingValue = newEntry.Value; + buckets[index] = newEntry; } - - var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); - this.buckets = nextBucket; - if (success) - this.size++; - - return success; } else { - var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); - if (success) - this.size++; - - return success; - } - - #region Local Functions - //--- please pass 'key + newEntry' or 'key + value'. - static bool AddToBuckets(Entry[] buckets, sbyte newKey, Entry newEntry, TValue value, out TValue resultingValue) - { - var hash = newEntry?.Hash ?? newKey.GetHashCode(); - var index = hash & (buckets.Length - 1); - if (buckets[index] is null) + var lastEntry = buckets[index]; + while (true) { - if (newEntry is null) + if (lastEntry.Key == newKey) { - resultingValue = value; - buckets[index] = new Entry(newKey, resultingValue, hash); + resultingValue = lastEntry.Value; + return false; } - else - { - resultingValue = newEntry.Value; - buckets[index] = newEntry; - } - } - else - { - var lastEntry = buckets[index]; - while (true) + + if (lastEntry.Next is null) { - if (lastEntry.Key == newKey) + if (newEntry is null) { - resultingValue = lastEntry.Value; - return false; + resultingValue = value; + lastEntry.Next = new Entry(newKey, resultingValue, hash); } - - if (lastEntry.Next is null) + else { - if (newEntry is null) - { - resultingValue = value; - lastEntry.Next = new Entry(newKey, resultingValue, hash); - } - else - { - resultingValue = newEntry.Value; - lastEntry.Next = newEntry; - } - break; + resultingValue = newEntry.Value; + lastEntry.Next = newEntry; } - - lastEntry = lastEntry.Next; + break; } + + lastEntry = lastEntry.Next; } - return true; } - #endregion + return true; } + #endregion + } - /// - /// Calculates bucket capacity. - /// - /// - /// - /// - private static int CalculateCapacity(int collectionSize, float loadFactor) - { - var initialCapacity = (int)(collectionSize / loadFactor); - var capacity = 1; - while (capacity < initialCapacity) - capacity <<= 1; + /// + /// Calculates bucket capacity. + /// + /// + /// + /// + private static int CalculateCapacity(int collectionSize, float loadFactor) + { + var initialCapacity = (int)(collectionSize / loadFactor); + var capacity = 1; + while (capacity < initialCapacity) + capacity <<= 1; - if (capacity < 8) - return 8; + if (capacity < 8) + return 8; - return capacity; - } - #endregion + return capacity; + } + #endregion - #region Get - /// - /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. - /// - /// - /// - /// - public TValue GetValueOrDefault(sbyte key, TValue defaultValue = default) - => this.TryGetValue(key, out var value) - ? value - : defaultValue; - #endregion + #region Get + /// + /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. + /// + /// + /// + /// + public TValue GetValueOrDefault(sbyte key, TValue defaultValue = default) + => this.TryGetValue(key, out var value) + ? value + : defaultValue; + #endregion + + + #region IReadOnlyDictionary implementations + /// + /// Gets the element that has the specified key in the read-only dictionary. + /// + /// The key to locate. + /// The element that has the specified key in the read-only dictionary. + public TValue this[sbyte key] + => this.TryGetValue(key, out var value) + ? value + : throw new KeyNotFoundException(); + + + /// + /// Gets an enumerable collection that contains the keys in the read-only dictionary. + /// + public IEnumerable Keys + => throw new NotImplementedException(); + + + /// + /// Gets an enumerable collection that contains the values in the read-only dictionary. + /// + public IEnumerable Values + => throw new NotImplementedException(); + + + /// + /// Gets the number of elements in the collection. + /// + public int Count + => this.size; + + + /// + /// Determines whether the read-only dictionary contains an element that has the specified key. + /// + /// The key to locate. + /// + /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. + /// + public bool ContainsKey(sbyte key) + => this.TryGetValue(key, out _); - #region IReadOnlyDictionary implementations - /// - /// Gets the element that has the specified key in the read-only dictionary. - /// - /// The key to locate. - /// The element that has the specified key in the read-only dictionary. - public TValue this[sbyte key] - => this.TryGetValue(key, out var value) - ? value - : throw new KeyNotFoundException(); - - - /// - /// Gets an enumerable collection that contains the keys in the read-only dictionary. - /// - public IEnumerable Keys - => throw new NotImplementedException(); - - - /// - /// Gets an enumerable collection that contains the values in the read-only dictionary. - /// - public IEnumerable Values - => throw new NotImplementedException(); - - - /// - /// Gets the number of elements in the collection. - /// - public int Count - => this.size; - - - /// - /// Determines whether the read-only dictionary contains an element that has the specified key. - /// - /// The key to locate. - /// - /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. - /// - public bool ContainsKey(sbyte key) - => this.TryGetValue(key, out _); - - - /// - /// Gets the value that is associated with the specified key. - /// - /// The key to locate. - /// - /// When this method returns, the value associated with the specified key, if the key is found; - /// otherwise, the default value for the type of the value parameter. - /// This parameter is passed uninitialized. - /// - /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetValue(sbyte key, out TValue value) + /// + /// Gets the value that is associated with the specified key. + /// + /// The key to locate. + /// + /// When this method returns, the value associated with the specified key, if the key is found; + /// otherwise, the default value for the type of the value parameter. + /// This parameter is passed uninitialized. + /// + /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(sbyte key, out TValue value) + { + var hash = key.GetHashCode(); + var index = hash & (this.buckets.Length - 1); + var next = this.buckets[index]; + while (next is not null) { - var hash = key.GetHashCode(); - var index = hash & (this.buckets.Length - 1); - var next = this.buckets[index]; - while (next is not null) + if (next.Key == key) { - if (next.Key == key) - { - value = next.Value; - return true; - } - next = next.Next; + value = next.Value; + return true; } - value = default; - return false; + next = next.Next; } + value = default; + return false; + } - /// - /// Returns an enumerator that iterates through the collection. - /// - /// An enumerator that can be used to iterate through the collection. - public IEnumerator> GetEnumerator() - => throw new NotImplementedException(); + /// + /// Returns an enumerator that iterates through the collection. + /// + /// An enumerator that can be used to iterate through the collection. + public IEnumerator> GetEnumerator() + => throw new NotImplementedException(); - /// - /// Returns an enumerator that iterates through a collection. - /// - /// An object that can be used to iterate through the collection. - IEnumerator IEnumerable.GetEnumerator() - => throw new NotImplementedException(); - #endregion + /// + /// Returns an enumerator that iterates through a collection. + /// + /// An object that can be used to iterate through the collection. + IEnumerator IEnumerable.GetEnumerator() + => throw new NotImplementedException(); + #endregion - #region Inner Classes - /// - /// Represents entry. - /// - private class Entry - { - public readonly sbyte Key; - public readonly TValue Value; - public readonly int Hash; - public Entry Next; + #region Inner Classes + /// + /// Represents entry. + /// + private class Entry + { + public readonly sbyte Key; + public readonly TValue Value; + public readonly int Hash; + public Entry Next; - public Entry(sbyte key, TValue value, int hash) - { - this.Key = key; - this.Value = value; - this.Hash = hash; - } + public Entry(sbyte key, TValue value, int hash) + { + this.Key = key; + this.Value = value; + this.Hash = hash; } - #endregion } + #endregion +} + +/// +/// Provides a read-only dictionary that contents are fixed at the time of instance creation. +/// +/// The type of values in the dictionary. +/// +/// Reference: +/// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs +/// +/// This class is byte specialized . +/// +internal sealed class FrozenByteKeyDictionary : IReadOnlyDictionary +{ + #region Constants + private static readonly Func PassThrough = x => x; + #endregion + + + #region Fields + private Entry[] buckets; + private int size; + private readonly float loadFactor; + #endregion + + #region Constructors /// - /// Provides a read-only dictionary that contents are fixed at the time of instance creation. + /// Creates instance. /// - /// The type of values in the dictionary. - /// - /// Reference: - /// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs - /// - /// This class is byte specialized . - /// - internal sealed class FrozenByteKeyDictionary : IReadOnlyDictionary + /// + /// + private FrozenByteKeyDictionary(int bucketSize, float loadFactor) { - #region Constants - private static readonly Func PassThrough = x => x; - #endregion + this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; + this.loadFactor = loadFactor; + } + #endregion - #region Fields - private Entry[] buckets; - private int size; - private readonly float loadFactor; - #endregion + #region Create + /// + /// Creates a from an according to a specified key selector function. + /// + /// + /// + /// + public static FrozenByteKeyDictionary Create(IEnumerable source, Func keySelector) + => Create(source, keySelector, PassThrough); + + /// + /// Creates a from an according to specified key selector and value selector functions. + /// + /// + /// + /// + /// + /// + public static FrozenByteKeyDictionary Create(IEnumerable source, Func keySelector, Func valueSelector) + { + const int initialSize = 4; + const float loadFactor = 0.75f; + var size = source.CountIfMaterialized() ?? initialSize; + var bucketSize = CalculateCapacity(size, loadFactor); + var result = new FrozenByteKeyDictionary(bucketSize, loadFactor); - #region Constructors - /// - /// Creates instance. - /// - /// - /// - private FrozenByteKeyDictionary(int bucketSize, float loadFactor) + foreach (var x in source) { - this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; - this.loadFactor = loadFactor; + var key = keySelector(x); + var value = valueSelector(x); + if (!result.TryAddInternal(key, value, out _)) + throw new ArgumentException($"Key was already exists. Key:{key}"); } - #endregion + return result; + } + #endregion - #region Create - /// - /// Creates a from an according to a specified key selector function. - /// - /// - /// - /// - public static FrozenByteKeyDictionary Create(IEnumerable source, Func keySelector) - => Create(source, keySelector, PassThrough); - - - /// - /// Creates a from an according to specified key selector and value selector functions. - /// - /// - /// - /// - /// - /// - public static FrozenByteKeyDictionary Create(IEnumerable source, Func keySelector, Func valueSelector) - { - const int initialSize = 4; - const float loadFactor = 0.75f; - var size = source.CountIfMaterialized() ?? initialSize; - var bucketSize = CalculateCapacity(size, loadFactor); - var result = new FrozenByteKeyDictionary(bucketSize, loadFactor); - foreach (var x in source) + #region Add + /// + /// Add element. + /// + /// + /// + /// + /// + private bool TryAddInternal(byte key, TValue value, out TValue resultingValue) + { + var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); + if (this.buckets.Length < nextCapacity) + { + //--- rehash + var nextBucket = new Entry[nextCapacity]; + for (int i = 0; i < this.buckets.Length; i++) { - var key = keySelector(x); - var value = valueSelector(x); - if (!result.TryAddInternal(key, value, out _)) - throw new ArgumentException($"Key was already exists. Key:{key}"); + var e = this.buckets[i]; + while (e is not null) + { + var newEntry = new Entry(e.Key, e.Value, e.Hash); + AddToBuckets(nextBucket, key, newEntry, default, out _); + e = e.Next; + } } - return result; + var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); + this.buckets = nextBucket; + if (success) + this.size++; + + return success; } - #endregion + else + { + var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); + if (success) + this.size++; + return success; + } - #region Add - /// - /// Add element. - /// - /// - /// - /// - /// - private bool TryAddInternal(byte key, TValue value, out TValue resultingValue) + #region Local Functions + //--- please pass 'key + newEntry' or 'key + value'. + static bool AddToBuckets(Entry[] buckets, byte newKey, Entry newEntry, TValue value, out TValue resultingValue) { - var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); - if (this.buckets.Length < nextCapacity) + var hash = newEntry?.Hash ?? newKey.GetHashCode(); + var index = hash & (buckets.Length - 1); + if (buckets[index] is null) { - //--- rehash - var nextBucket = new Entry[nextCapacity]; - for (int i = 0; i < this.buckets.Length; i++) + if (newEntry is null) { - var e = this.buckets[i]; - while (e is not null) - { - var newEntry = new Entry(e.Key, e.Value, e.Hash); - AddToBuckets(nextBucket, key, newEntry, default, out _); - e = e.Next; - } + resultingValue = value; + buckets[index] = new Entry(newKey, resultingValue, hash); + } + else + { + resultingValue = newEntry.Value; + buckets[index] = newEntry; } - - var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); - this.buckets = nextBucket; - if (success) - this.size++; - - return success; } else { - var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); - if (success) - this.size++; - - return success; - } - - #region Local Functions - //--- please pass 'key + newEntry' or 'key + value'. - static bool AddToBuckets(Entry[] buckets, byte newKey, Entry newEntry, TValue value, out TValue resultingValue) - { - var hash = newEntry?.Hash ?? newKey.GetHashCode(); - var index = hash & (buckets.Length - 1); - if (buckets[index] is null) + var lastEntry = buckets[index]; + while (true) { - if (newEntry is null) - { - resultingValue = value; - buckets[index] = new Entry(newKey, resultingValue, hash); - } - else + if (lastEntry.Key == newKey) { - resultingValue = newEntry.Value; - buckets[index] = newEntry; + resultingValue = lastEntry.Value; + return false; } - } - else - { - var lastEntry = buckets[index]; - while (true) + + if (lastEntry.Next is null) { - if (lastEntry.Key == newKey) + if (newEntry is null) { - resultingValue = lastEntry.Value; - return false; + resultingValue = value; + lastEntry.Next = new Entry(newKey, resultingValue, hash); } - - if (lastEntry.Next is null) + else { - if (newEntry is null) - { - resultingValue = value; - lastEntry.Next = new Entry(newKey, resultingValue, hash); - } - else - { - resultingValue = newEntry.Value; - lastEntry.Next = newEntry; - } - break; + resultingValue = newEntry.Value; + lastEntry.Next = newEntry; } - - lastEntry = lastEntry.Next; + break; } + + lastEntry = lastEntry.Next; } - return true; } - #endregion + return true; } + #endregion + } - /// - /// Calculates bucket capacity. - /// - /// - /// - /// - private static int CalculateCapacity(int collectionSize, float loadFactor) - { - var initialCapacity = (int)(collectionSize / loadFactor); - var capacity = 1; - while (capacity < initialCapacity) - capacity <<= 1; + /// + /// Calculates bucket capacity. + /// + /// + /// + /// + private static int CalculateCapacity(int collectionSize, float loadFactor) + { + var initialCapacity = (int)(collectionSize / loadFactor); + var capacity = 1; + while (capacity < initialCapacity) + capacity <<= 1; - if (capacity < 8) - return 8; + if (capacity < 8) + return 8; - return capacity; - } - #endregion + return capacity; + } + #endregion - #region Get - /// - /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. - /// - /// - /// - /// - public TValue GetValueOrDefault(byte key, TValue defaultValue = default) - => this.TryGetValue(key, out var value) - ? value - : defaultValue; - #endregion + #region Get + /// + /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. + /// + /// + /// + /// + public TValue GetValueOrDefault(byte key, TValue defaultValue = default) + => this.TryGetValue(key, out var value) + ? value + : defaultValue; + #endregion + + + #region IReadOnlyDictionary implementations + /// + /// Gets the element that has the specified key in the read-only dictionary. + /// + /// The key to locate. + /// The element that has the specified key in the read-only dictionary. + public TValue this[byte key] + => this.TryGetValue(key, out var value) + ? value + : throw new KeyNotFoundException(); + + /// + /// Gets an enumerable collection that contains the keys in the read-only dictionary. + /// + public IEnumerable Keys + => throw new NotImplementedException(); + + + /// + /// Gets an enumerable collection that contains the values in the read-only dictionary. + /// + public IEnumerable Values + => throw new NotImplementedException(); + + + /// + /// Gets the number of elements in the collection. + /// + public int Count + => this.size; + + + /// + /// Determines whether the read-only dictionary contains an element that has the specified key. + /// + /// The key to locate. + /// + /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. + /// + public bool ContainsKey(byte key) + => this.TryGetValue(key, out _); - #region IReadOnlyDictionary implementations - /// - /// Gets the element that has the specified key in the read-only dictionary. - /// - /// The key to locate. - /// The element that has the specified key in the read-only dictionary. - public TValue this[byte key] - => this.TryGetValue(key, out var value) - ? value - : throw new KeyNotFoundException(); - - - /// - /// Gets an enumerable collection that contains the keys in the read-only dictionary. - /// - public IEnumerable Keys - => throw new NotImplementedException(); - - - /// - /// Gets an enumerable collection that contains the values in the read-only dictionary. - /// - public IEnumerable Values - => throw new NotImplementedException(); - - - /// - /// Gets the number of elements in the collection. - /// - public int Count - => this.size; - - - /// - /// Determines whether the read-only dictionary contains an element that has the specified key. - /// - /// The key to locate. - /// - /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. - /// - public bool ContainsKey(byte key) - => this.TryGetValue(key, out _); - - - /// - /// Gets the value that is associated with the specified key. - /// - /// The key to locate. - /// - /// When this method returns, the value associated with the specified key, if the key is found; - /// otherwise, the default value for the type of the value parameter. - /// This parameter is passed uninitialized. - /// - /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetValue(byte key, out TValue value) + + /// + /// Gets the value that is associated with the specified key. + /// + /// The key to locate. + /// + /// When this method returns, the value associated with the specified key, if the key is found; + /// otherwise, the default value for the type of the value parameter. + /// This parameter is passed uninitialized. + /// + /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(byte key, out TValue value) + { + var hash = key.GetHashCode(); + var index = hash & (this.buckets.Length - 1); + var next = this.buckets[index]; + while (next is not null) { - var hash = key.GetHashCode(); - var index = hash & (this.buckets.Length - 1); - var next = this.buckets[index]; - while (next is not null) + if (next.Key == key) { - if (next.Key == key) - { - value = next.Value; - return true; - } - next = next.Next; + value = next.Value; + return true; } - value = default; - return false; + next = next.Next; } + value = default; + return false; + } - /// - /// Returns an enumerator that iterates through the collection. - /// - /// An enumerator that can be used to iterate through the collection. - public IEnumerator> GetEnumerator() - => throw new NotImplementedException(); + /// + /// Returns an enumerator that iterates through the collection. + /// + /// An enumerator that can be used to iterate through the collection. + public IEnumerator> GetEnumerator() + => throw new NotImplementedException(); - /// - /// Returns an enumerator that iterates through a collection. - /// - /// An object that can be used to iterate through the collection. - IEnumerator IEnumerable.GetEnumerator() - => throw new NotImplementedException(); - #endregion + /// + /// Returns an enumerator that iterates through a collection. + /// + /// An object that can be used to iterate through the collection. + IEnumerator IEnumerable.GetEnumerator() + => throw new NotImplementedException(); + #endregion - #region Inner Classes - /// - /// Represents entry. - /// - private class Entry - { - public readonly byte Key; - public readonly TValue Value; - public readonly int Hash; - public Entry Next; + #region Inner Classes + /// + /// Represents entry. + /// + private class Entry + { + public readonly byte Key; + public readonly TValue Value; + public readonly int Hash; + public Entry Next; - public Entry(byte key, TValue value, int hash) - { - this.Key = key; - this.Value = value; - this.Hash = hash; - } + public Entry(byte key, TValue value, int hash) + { + this.Key = key; + this.Value = value; + this.Hash = hash; } - #endregion } + #endregion +} + + + +/// +/// Provides a read-only dictionary that contents are fixed at the time of instance creation. +/// +/// The type of values in the dictionary. +/// +/// Reference: +/// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs +/// +/// This class is short specialized . +/// +internal sealed class FrozenInt16KeyDictionary : IReadOnlyDictionary +{ + #region Constants + private static readonly Func PassThrough = x => x; + #endregion + #region Fields + private Entry[] buckets; + private int size; + private readonly float loadFactor; + #endregion + + #region Constructors /// - /// Provides a read-only dictionary that contents are fixed at the time of instance creation. + /// Creates instance. /// - /// The type of values in the dictionary. - /// - /// Reference: - /// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs - /// - /// This class is short specialized . - /// - internal sealed class FrozenInt16KeyDictionary : IReadOnlyDictionary + /// + /// + private FrozenInt16KeyDictionary(int bucketSize, float loadFactor) { - #region Constants - private static readonly Func PassThrough = x => x; - #endregion + this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; + this.loadFactor = loadFactor; + } + #endregion - #region Fields - private Entry[] buckets; - private int size; - private readonly float loadFactor; - #endregion + #region Create + /// + /// Creates a from an according to a specified key selector function. + /// + /// + /// + /// + public static FrozenInt16KeyDictionary Create(IEnumerable source, Func keySelector) + => Create(source, keySelector, PassThrough); - #region Constructors - /// - /// Creates instance. - /// - /// - /// - private FrozenInt16KeyDictionary(int bucketSize, float loadFactor) + /// + /// Creates a from an according to specified key selector and value selector functions. + /// + /// + /// + /// + /// + /// + public static FrozenInt16KeyDictionary Create(IEnumerable source, Func keySelector, Func valueSelector) + { + const int initialSize = 4; + const float loadFactor = 0.75f; + var size = source.CountIfMaterialized() ?? initialSize; + var bucketSize = CalculateCapacity(size, loadFactor); + var result = new FrozenInt16KeyDictionary(bucketSize, loadFactor); + + foreach (var x in source) { - this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; - this.loadFactor = loadFactor; + var key = keySelector(x); + var value = valueSelector(x); + if (!result.TryAddInternal(key, value, out _)) + throw new ArgumentException($"Key was already exists. Key:{key}"); } - #endregion + return result; + } + #endregion - #region Create - /// - /// Creates a from an according to a specified key selector function. - /// - /// - /// - /// - public static FrozenInt16KeyDictionary Create(IEnumerable source, Func keySelector) - => Create(source, keySelector, PassThrough); - - - /// - /// Creates a from an according to specified key selector and value selector functions. - /// - /// - /// - /// - /// - /// - public static FrozenInt16KeyDictionary Create(IEnumerable source, Func keySelector, Func valueSelector) - { - const int initialSize = 4; - const float loadFactor = 0.75f; - var size = source.CountIfMaterialized() ?? initialSize; - var bucketSize = CalculateCapacity(size, loadFactor); - var result = new FrozenInt16KeyDictionary(bucketSize, loadFactor); - foreach (var x in source) + #region Add + /// + /// Add element. + /// + /// + /// + /// + /// + private bool TryAddInternal(short key, TValue value, out TValue resultingValue) + { + var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); + if (this.buckets.Length < nextCapacity) + { + //--- rehash + var nextBucket = new Entry[nextCapacity]; + for (int i = 0; i < this.buckets.Length; i++) { - var key = keySelector(x); - var value = valueSelector(x); - if (!result.TryAddInternal(key, value, out _)) - throw new ArgumentException($"Key was already exists. Key:{key}"); + var e = this.buckets[i]; + while (e is not null) + { + var newEntry = new Entry(e.Key, e.Value, e.Hash); + AddToBuckets(nextBucket, key, newEntry, default, out _); + e = e.Next; + } } - return result; + var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); + this.buckets = nextBucket; + if (success) + this.size++; + + return success; } - #endregion + else + { + var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); + if (success) + this.size++; + return success; + } - #region Add - /// - /// Add element. - /// - /// - /// - /// - /// - private bool TryAddInternal(short key, TValue value, out TValue resultingValue) + #region Local Functions + //--- please pass 'key + newEntry' or 'key + value'. + static bool AddToBuckets(Entry[] buckets, short newKey, Entry newEntry, TValue value, out TValue resultingValue) { - var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); - if (this.buckets.Length < nextCapacity) + var hash = newEntry?.Hash ?? newKey.GetHashCode(); + var index = hash & (buckets.Length - 1); + if (buckets[index] is null) { - //--- rehash - var nextBucket = new Entry[nextCapacity]; - for (int i = 0; i < this.buckets.Length; i++) + if (newEntry is null) { - var e = this.buckets[i]; - while (e is not null) - { - var newEntry = new Entry(e.Key, e.Value, e.Hash); - AddToBuckets(nextBucket, key, newEntry, default, out _); - e = e.Next; - } + resultingValue = value; + buckets[index] = new Entry(newKey, resultingValue, hash); + } + else + { + resultingValue = newEntry.Value; + buckets[index] = newEntry; } - - var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); - this.buckets = nextBucket; - if (success) - this.size++; - - return success; } else { - var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); - if (success) - this.size++; - - return success; - } - - #region Local Functions - //--- please pass 'key + newEntry' or 'key + value'. - static bool AddToBuckets(Entry[] buckets, short newKey, Entry newEntry, TValue value, out TValue resultingValue) - { - var hash = newEntry?.Hash ?? newKey.GetHashCode(); - var index = hash & (buckets.Length - 1); - if (buckets[index] is null) + var lastEntry = buckets[index]; + while (true) { - if (newEntry is null) - { - resultingValue = value; - buckets[index] = new Entry(newKey, resultingValue, hash); - } - else + if (lastEntry.Key == newKey) { - resultingValue = newEntry.Value; - buckets[index] = newEntry; + resultingValue = lastEntry.Value; + return false; } - } - else - { - var lastEntry = buckets[index]; - while (true) + + if (lastEntry.Next is null) { - if (lastEntry.Key == newKey) + if (newEntry is null) { - resultingValue = lastEntry.Value; - return false; + resultingValue = value; + lastEntry.Next = new Entry(newKey, resultingValue, hash); } - - if (lastEntry.Next is null) + else { - if (newEntry is null) - { - resultingValue = value; - lastEntry.Next = new Entry(newKey, resultingValue, hash); - } - else - { - resultingValue = newEntry.Value; - lastEntry.Next = newEntry; - } - break; + resultingValue = newEntry.Value; + lastEntry.Next = newEntry; } - - lastEntry = lastEntry.Next; + break; } + + lastEntry = lastEntry.Next; } - return true; } - #endregion + return true; } + #endregion + } - /// - /// Calculates bucket capacity. - /// - /// - /// - /// - private static int CalculateCapacity(int collectionSize, float loadFactor) - { - var initialCapacity = (int)(collectionSize / loadFactor); - var capacity = 1; - while (capacity < initialCapacity) - capacity <<= 1; + /// + /// Calculates bucket capacity. + /// + /// + /// + /// + private static int CalculateCapacity(int collectionSize, float loadFactor) + { + var initialCapacity = (int)(collectionSize / loadFactor); + var capacity = 1; + while (capacity < initialCapacity) + capacity <<= 1; - if (capacity < 8) - return 8; + if (capacity < 8) + return 8; - return capacity; - } - #endregion + return capacity; + } + #endregion - #region Get - /// - /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. - /// - /// - /// - /// - public TValue GetValueOrDefault(short key, TValue defaultValue = default) - => this.TryGetValue(key, out var value) - ? value - : defaultValue; - #endregion + #region Get + /// + /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. + /// + /// + /// + /// + public TValue GetValueOrDefault(short key, TValue defaultValue = default) + => this.TryGetValue(key, out var value) + ? value + : defaultValue; + #endregion - #region IReadOnlyDictionary implementations - /// - /// Gets the element that has the specified key in the read-only dictionary. - /// - /// The key to locate. - /// The element that has the specified key in the read-only dictionary. - public TValue this[short key] - => this.TryGetValue(key, out var value) - ? value - : throw new KeyNotFoundException(); - - - /// - /// Gets an enumerable collection that contains the keys in the read-only dictionary. - /// - public IEnumerable Keys - => throw new NotImplementedException(); - - - /// - /// Gets an enumerable collection that contains the values in the read-only dictionary. - /// - public IEnumerable Values - => throw new NotImplementedException(); - - - /// - /// Gets the number of elements in the collection. - /// - public int Count - => this.size; - - - /// - /// Determines whether the read-only dictionary contains an element that has the specified key. - /// - /// The key to locate. - /// - /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. - /// - public bool ContainsKey(short key) - => this.TryGetValue(key, out _); - - - /// - /// Gets the value that is associated with the specified key. - /// - /// The key to locate. - /// - /// When this method returns, the value associated with the specified key, if the key is found; - /// otherwise, the default value for the type of the value parameter. - /// This parameter is passed uninitialized. - /// - /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetValue(short key, out TValue value) - { - var hash = key.GetHashCode(); - var index = hash & (this.buckets.Length - 1); - var next = this.buckets[index]; - while (next is not null) - { - if (next.Key == key) - { - value = next.Value; - return true; - } - next = next.Next; - } - value = default; - return false; - } + #region IReadOnlyDictionary implementations + /// + /// Gets the element that has the specified key in the read-only dictionary. + /// + /// The key to locate. + /// The element that has the specified key in the read-only dictionary. + public TValue this[short key] + => this.TryGetValue(key, out var value) + ? value + : throw new KeyNotFoundException(); - /// - /// Returns an enumerator that iterates through the collection. - /// - /// An enumerator that can be used to iterate through the collection. - public IEnumerator> GetEnumerator() - => throw new NotImplementedException(); + /// + /// Gets an enumerable collection that contains the keys in the read-only dictionary. + /// + public IEnumerable Keys + => throw new NotImplementedException(); - /// - /// Returns an enumerator that iterates through a collection. - /// - /// An object that can be used to iterate through the collection. - IEnumerator IEnumerable.GetEnumerator() - => throw new NotImplementedException(); - #endregion + /// + /// Gets an enumerable collection that contains the values in the read-only dictionary. + /// + public IEnumerable Values + => throw new NotImplementedException(); - #region Inner Classes - /// - /// Represents entry. - /// - private class Entry - { - public readonly short Key; - public readonly TValue Value; - public readonly int Hash; - public Entry Next; + /// + /// Gets the number of elements in the collection. + /// + public int Count + => this.size; - public Entry(short key, TValue value, int hash) + + /// + /// Determines whether the read-only dictionary contains an element that has the specified key. + /// + /// The key to locate. + /// + /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. + /// + public bool ContainsKey(short key) + => this.TryGetValue(key, out _); + + + /// + /// Gets the value that is associated with the specified key. + /// + /// The key to locate. + /// + /// When this method returns, the value associated with the specified key, if the key is found; + /// otherwise, the default value for the type of the value parameter. + /// This parameter is passed uninitialized. + /// + /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(short key, out TValue value) + { + var hash = key.GetHashCode(); + var index = hash & (this.buckets.Length - 1); + var next = this.buckets[index]; + while (next is not null) + { + if (next.Key == key) { - this.Key = key; - this.Value = value; - this.Hash = hash; + value = next.Value; + return true; } + next = next.Next; } - #endregion + value = default; + return false; } - /// - /// Provides a read-only dictionary that contents are fixed at the time of instance creation. + /// Returns an enumerator that iterates through the collection. /// - /// The type of values in the dictionary. - /// - /// Reference: - /// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs - /// - /// This class is ushort specialized . - /// - internal sealed class FrozenUInt16KeyDictionary : IReadOnlyDictionary - { - #region Constants - private static readonly Func PassThrough = x => x; - #endregion + /// An enumerator that can be used to iterate through the collection. + public IEnumerator> GetEnumerator() + => throw new NotImplementedException(); - #region Fields - private Entry[] buckets; - private int size; - private readonly float loadFactor; - #endregion + /// + /// Returns an enumerator that iterates through a collection. + /// + /// An object that can be used to iterate through the collection. + IEnumerator IEnumerable.GetEnumerator() + => throw new NotImplementedException(); + #endregion + + #region Inner Classes + /// + /// Represents entry. + /// + private class Entry + { + public readonly short Key; + public readonly TValue Value; + public readonly int Hash; + public Entry Next; - #region Constructors - /// - /// Creates instance. - /// - /// - /// - private FrozenUInt16KeyDictionary(int bucketSize, float loadFactor) + public Entry(short key, TValue value, int hash) { - this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; - this.loadFactor = loadFactor; + this.Key = key; + this.Value = value; + this.Hash = hash; } - #endregion + } + #endregion +} - #region Create - /// - /// Creates a from an according to a specified key selector function. - /// - /// - /// - /// - public static FrozenUInt16KeyDictionary Create(IEnumerable source, Func keySelector) - => Create(source, keySelector, PassThrough); - - - /// - /// Creates a from an according to specified key selector and value selector functions. - /// - /// - /// - /// - /// - /// - public static FrozenUInt16KeyDictionary Create(IEnumerable source, Func keySelector, Func valueSelector) - { - const int initialSize = 4; - const float loadFactor = 0.75f; - var size = source.CountIfMaterialized() ?? initialSize; - var bucketSize = CalculateCapacity(size, loadFactor); - var result = new FrozenUInt16KeyDictionary(bucketSize, loadFactor); - foreach (var x in source) - { - var key = keySelector(x); - var value = valueSelector(x); - if (!result.TryAddInternal(key, value, out _)) - throw new ArgumentException($"Key was already exists. Key:{key}"); - } +/// +/// Provides a read-only dictionary that contents are fixed at the time of instance creation. +/// +/// The type of values in the dictionary. +/// +/// Reference: +/// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs +/// +/// This class is ushort specialized . +/// +internal sealed class FrozenUInt16KeyDictionary : IReadOnlyDictionary +{ + #region Constants + private static readonly Func PassThrough = x => x; + #endregion - return result; - } - #endregion + #region Fields + private Entry[] buckets; + private int size; + private readonly float loadFactor; + #endregion - #region Add - /// - /// Add element. - /// - /// - /// - /// - /// - private bool TryAddInternal(ushort key, TValue value, out TValue resultingValue) - { - var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); - if (this.buckets.Length < nextCapacity) - { - //--- rehash - var nextBucket = new Entry[nextCapacity]; - for (int i = 0; i < this.buckets.Length; i++) + + #region Constructors + /// + /// Creates instance. + /// + /// + /// + private FrozenUInt16KeyDictionary(int bucketSize, float loadFactor) + { + this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; + this.loadFactor = loadFactor; + } + #endregion + + + #region Create + /// + /// Creates a from an according to a specified key selector function. + /// + /// + /// + /// + public static FrozenUInt16KeyDictionary Create(IEnumerable source, Func keySelector) + => Create(source, keySelector, PassThrough); + + + /// + /// Creates a from an according to specified key selector and value selector functions. + /// + /// + /// + /// + /// + /// + public static FrozenUInt16KeyDictionary Create(IEnumerable source, Func keySelector, Func valueSelector) + { + const int initialSize = 4; + const float loadFactor = 0.75f; + var size = source.CountIfMaterialized() ?? initialSize; + var bucketSize = CalculateCapacity(size, loadFactor); + var result = new FrozenUInt16KeyDictionary(bucketSize, loadFactor); + + foreach (var x in source) + { + var key = keySelector(x); + var value = valueSelector(x); + if (!result.TryAddInternal(key, value, out _)) + throw new ArgumentException($"Key was already exists. Key:{key}"); + } + + return result; + } + #endregion + + + #region Add + /// + /// Add element. + /// + /// + /// + /// + /// + private bool TryAddInternal(ushort key, TValue value, out TValue resultingValue) + { + var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); + if (this.buckets.Length < nextCapacity) + { + //--- rehash + var nextBucket = new Entry[nextCapacity]; + for (int i = 0; i < this.buckets.Length; i++) + { + var e = this.buckets[i]; + while (e is not null) { - var e = this.buckets[i]; - while (e is not null) - { - var newEntry = new Entry(e.Key, e.Value, e.Hash); - AddToBuckets(nextBucket, key, newEntry, default, out _); - e = e.Next; - } + var newEntry = new Entry(e.Key, e.Value, e.Hash); + AddToBuckets(nextBucket, key, newEntry, default, out _); + e = e.Next; } + } - var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); - this.buckets = nextBucket; - if (success) - this.size++; + var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); + this.buckets = nextBucket; + if (success) + this.size++; - return success; - } - else - { - var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); - if (success) - this.size++; + return success; + } + else + { + var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); + if (success) + this.size++; - return success; - } + return success; + } - #region Local Functions - //--- please pass 'key + newEntry' or 'key + value'. - static bool AddToBuckets(Entry[] buckets, ushort newKey, Entry newEntry, TValue value, out TValue resultingValue) + #region Local Functions + //--- please pass 'key + newEntry' or 'key + value'. + static bool AddToBuckets(Entry[] buckets, ushort newKey, Entry newEntry, TValue value, out TValue resultingValue) + { + var hash = newEntry?.Hash ?? newKey.GetHashCode(); + var index = hash & (buckets.Length - 1); + if (buckets[index] is null) { - var hash = newEntry?.Hash ?? newKey.GetHashCode(); - var index = hash & (buckets.Length - 1); - if (buckets[index] is null) + if (newEntry is null) { - if (newEntry is null) - { - resultingValue = value; - buckets[index] = new Entry(newKey, resultingValue, hash); - } - else - { - resultingValue = newEntry.Value; - buckets[index] = newEntry; - } + resultingValue = value; + buckets[index] = new Entry(newKey, resultingValue, hash); } else { - var lastEntry = buckets[index]; - while (true) + resultingValue = newEntry.Value; + buckets[index] = newEntry; + } + } + else + { + var lastEntry = buckets[index]; + while (true) + { + if (lastEntry.Key == newKey) + { + resultingValue = lastEntry.Value; + return false; + } + + if (lastEntry.Next is null) { - if (lastEntry.Key == newKey) + if (newEntry is null) { - resultingValue = lastEntry.Value; - return false; + resultingValue = value; + lastEntry.Next = new Entry(newKey, resultingValue, hash); } - - if (lastEntry.Next is null) + else { - if (newEntry is null) - { - resultingValue = value; - lastEntry.Next = new Entry(newKey, resultingValue, hash); - } - else - { - resultingValue = newEntry.Value; - lastEntry.Next = newEntry; - } - break; + resultingValue = newEntry.Value; + lastEntry.Next = newEntry; } - - lastEntry = lastEntry.Next; + break; } + + lastEntry = lastEntry.Next; } - return true; } - #endregion + return true; } + #endregion + } - /// - /// Calculates bucket capacity. - /// - /// - /// - /// - private static int CalculateCapacity(int collectionSize, float loadFactor) - { - var initialCapacity = (int)(collectionSize / loadFactor); - var capacity = 1; - while (capacity < initialCapacity) - capacity <<= 1; + /// + /// Calculates bucket capacity. + /// + /// + /// + /// + private static int CalculateCapacity(int collectionSize, float loadFactor) + { + var initialCapacity = (int)(collectionSize / loadFactor); + var capacity = 1; + while (capacity < initialCapacity) + capacity <<= 1; - if (capacity < 8) - return 8; + if (capacity < 8) + return 8; - return capacity; - } - #endregion + return capacity; + } + #endregion - #region Get - /// - /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. - /// - /// - /// - /// - public TValue GetValueOrDefault(ushort key, TValue defaultValue = default) - => this.TryGetValue(key, out var value) - ? value - : defaultValue; - #endregion + #region Get + /// + /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. + /// + /// + /// + /// + public TValue GetValueOrDefault(ushort key, TValue defaultValue = default) + => this.TryGetValue(key, out var value) + ? value + : defaultValue; + #endregion + + + #region IReadOnlyDictionary implementations + /// + /// Gets the element that has the specified key in the read-only dictionary. + /// + /// The key to locate. + /// The element that has the specified key in the read-only dictionary. + public TValue this[ushort key] + => this.TryGetValue(key, out var value) + ? value + : throw new KeyNotFoundException(); + + + /// + /// Gets an enumerable collection that contains the keys in the read-only dictionary. + /// + public IEnumerable Keys + => throw new NotImplementedException(); + + + /// + /// Gets an enumerable collection that contains the values in the read-only dictionary. + /// + public IEnumerable Values + => throw new NotImplementedException(); + + + /// + /// Gets the number of elements in the collection. + /// + public int Count + => this.size; + + + /// + /// Determines whether the read-only dictionary contains an element that has the specified key. + /// + /// The key to locate. + /// + /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. + /// + public bool ContainsKey(ushort key) + => this.TryGetValue(key, out _); - #region IReadOnlyDictionary implementations - /// - /// Gets the element that has the specified key in the read-only dictionary. - /// - /// The key to locate. - /// The element that has the specified key in the read-only dictionary. - public TValue this[ushort key] - => this.TryGetValue(key, out var value) - ? value - : throw new KeyNotFoundException(); - - - /// - /// Gets an enumerable collection that contains the keys in the read-only dictionary. - /// - public IEnumerable Keys - => throw new NotImplementedException(); - - - /// - /// Gets an enumerable collection that contains the values in the read-only dictionary. - /// - public IEnumerable Values - => throw new NotImplementedException(); - - - /// - /// Gets the number of elements in the collection. - /// - public int Count - => this.size; - - - /// - /// Determines whether the read-only dictionary contains an element that has the specified key. - /// - /// The key to locate. - /// - /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. - /// - public bool ContainsKey(ushort key) - => this.TryGetValue(key, out _); - - - /// - /// Gets the value that is associated with the specified key. - /// - /// The key to locate. - /// - /// When this method returns, the value associated with the specified key, if the key is found; - /// otherwise, the default value for the type of the value parameter. - /// This parameter is passed uninitialized. - /// - /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetValue(ushort key, out TValue value) + /// + /// Gets the value that is associated with the specified key. + /// + /// The key to locate. + /// + /// When this method returns, the value associated with the specified key, if the key is found; + /// otherwise, the default value for the type of the value parameter. + /// This parameter is passed uninitialized. + /// + /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(ushort key, out TValue value) + { + var hash = key.GetHashCode(); + var index = hash & (this.buckets.Length - 1); + var next = this.buckets[index]; + while (next is not null) { - var hash = key.GetHashCode(); - var index = hash & (this.buckets.Length - 1); - var next = this.buckets[index]; - while (next is not null) + if (next.Key == key) { - if (next.Key == key) - { - value = next.Value; - return true; - } - next = next.Next; + value = next.Value; + return true; } - value = default; - return false; + next = next.Next; } + value = default; + return false; + } - /// - /// Returns an enumerator that iterates through the collection. - /// - /// An enumerator that can be used to iterate through the collection. - public IEnumerator> GetEnumerator() - => throw new NotImplementedException(); + /// + /// Returns an enumerator that iterates through the collection. + /// + /// An enumerator that can be used to iterate through the collection. + public IEnumerator> GetEnumerator() + => throw new NotImplementedException(); - /// - /// Returns an enumerator that iterates through a collection. - /// - /// An object that can be used to iterate through the collection. - IEnumerator IEnumerable.GetEnumerator() - => throw new NotImplementedException(); - #endregion + /// + /// Returns an enumerator that iterates through a collection. + /// + /// An object that can be used to iterate through the collection. + IEnumerator IEnumerable.GetEnumerator() + => throw new NotImplementedException(); + #endregion - #region Inner Classes - /// - /// Represents entry. - /// - private class Entry - { - public readonly ushort Key; - public readonly TValue Value; - public readonly int Hash; - public Entry Next; + #region Inner Classes + /// + /// Represents entry. + /// + private class Entry + { + public readonly ushort Key; + public readonly TValue Value; + public readonly int Hash; + public Entry Next; - public Entry(ushort key, TValue value, int hash) - { - this.Key = key; - this.Value = value; - this.Hash = hash; - } + public Entry(ushort key, TValue value, int hash) + { + this.Key = key; + this.Value = value; + this.Hash = hash; } - #endregion } + #endregion +} + + + +/// +/// Provides a read-only dictionary that contents are fixed at the time of instance creation. +/// +/// The type of values in the dictionary. +/// +/// Reference: +/// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs +/// +/// This class is int specialized . +/// +internal sealed class FrozenInt32KeyDictionary : IReadOnlyDictionary +{ + #region Constants + private static readonly Func PassThrough = x => x; + #endregion + #region Fields + private Entry[] buckets; + private int size; + private readonly float loadFactor; + #endregion + + #region Constructors /// - /// Provides a read-only dictionary that contents are fixed at the time of instance creation. + /// Creates instance. /// - /// The type of values in the dictionary. - /// - /// Reference: - /// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs - /// - /// This class is int specialized . - /// - internal sealed class FrozenInt32KeyDictionary : IReadOnlyDictionary + /// + /// + private FrozenInt32KeyDictionary(int bucketSize, float loadFactor) { - #region Constants - private static readonly Func PassThrough = x => x; - #endregion + this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; + this.loadFactor = loadFactor; + } + #endregion - #region Fields - private Entry[] buckets; - private int size; - private readonly float loadFactor; - #endregion + #region Create + /// + /// Creates a from an according to a specified key selector function. + /// + /// + /// + /// + public static FrozenInt32KeyDictionary Create(IEnumerable source, Func keySelector) + => Create(source, keySelector, PassThrough); - #region Constructors - /// - /// Creates instance. - /// - /// - /// - private FrozenInt32KeyDictionary(int bucketSize, float loadFactor) + /// + /// Creates a from an according to specified key selector and value selector functions. + /// + /// + /// + /// + /// + /// + public static FrozenInt32KeyDictionary Create(IEnumerable source, Func keySelector, Func valueSelector) + { + const int initialSize = 4; + const float loadFactor = 0.75f; + var size = source.CountIfMaterialized() ?? initialSize; + var bucketSize = CalculateCapacity(size, loadFactor); + var result = new FrozenInt32KeyDictionary(bucketSize, loadFactor); + + foreach (var x in source) { - this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; - this.loadFactor = loadFactor; + var key = keySelector(x); + var value = valueSelector(x); + if (!result.TryAddInternal(key, value, out _)) + throw new ArgumentException($"Key was already exists. Key:{key}"); } - #endregion + return result; + } + #endregion - #region Create - /// - /// Creates a from an according to a specified key selector function. - /// - /// - /// - /// - public static FrozenInt32KeyDictionary Create(IEnumerable source, Func keySelector) - => Create(source, keySelector, PassThrough); - - - /// - /// Creates a from an according to specified key selector and value selector functions. - /// - /// - /// - /// - /// - /// - public static FrozenInt32KeyDictionary Create(IEnumerable source, Func keySelector, Func valueSelector) - { - const int initialSize = 4; - const float loadFactor = 0.75f; - var size = source.CountIfMaterialized() ?? initialSize; - var bucketSize = CalculateCapacity(size, loadFactor); - var result = new FrozenInt32KeyDictionary(bucketSize, loadFactor); - foreach (var x in source) + #region Add + /// + /// Add element. + /// + /// + /// + /// + /// + private bool TryAddInternal(int key, TValue value, out TValue resultingValue) + { + var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); + if (this.buckets.Length < nextCapacity) + { + //--- rehash + var nextBucket = new Entry[nextCapacity]; + for (int i = 0; i < this.buckets.Length; i++) { - var key = keySelector(x); - var value = valueSelector(x); - if (!result.TryAddInternal(key, value, out _)) - throw new ArgumentException($"Key was already exists. Key:{key}"); + var e = this.buckets[i]; + while (e is not null) + { + var newEntry = new Entry(e.Key, e.Value, e.Hash); + AddToBuckets(nextBucket, key, newEntry, default, out _); + e = e.Next; + } } - return result; + var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); + this.buckets = nextBucket; + if (success) + this.size++; + + return success; } - #endregion + else + { + var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); + if (success) + this.size++; + return success; + } - #region Add - /// - /// Add element. - /// - /// - /// - /// - /// - private bool TryAddInternal(int key, TValue value, out TValue resultingValue) + #region Local Functions + //--- please pass 'key + newEntry' or 'key + value'. + static bool AddToBuckets(Entry[] buckets, int newKey, Entry newEntry, TValue value, out TValue resultingValue) { - var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); - if (this.buckets.Length < nextCapacity) + var hash = newEntry?.Hash ?? newKey.GetHashCode(); + var index = hash & (buckets.Length - 1); + if (buckets[index] is null) { - //--- rehash - var nextBucket = new Entry[nextCapacity]; - for (int i = 0; i < this.buckets.Length; i++) + if (newEntry is null) { - var e = this.buckets[i]; - while (e is not null) - { - var newEntry = new Entry(e.Key, e.Value, e.Hash); - AddToBuckets(nextBucket, key, newEntry, default, out _); - e = e.Next; - } + resultingValue = value; + buckets[index] = new Entry(newKey, resultingValue, hash); + } + else + { + resultingValue = newEntry.Value; + buckets[index] = newEntry; } - - var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); - this.buckets = nextBucket; - if (success) - this.size++; - - return success; } else { - var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); - if (success) - this.size++; - - return success; - } - - #region Local Functions - //--- please pass 'key + newEntry' or 'key + value'. - static bool AddToBuckets(Entry[] buckets, int newKey, Entry newEntry, TValue value, out TValue resultingValue) - { - var hash = newEntry?.Hash ?? newKey.GetHashCode(); - var index = hash & (buckets.Length - 1); - if (buckets[index] is null) + var lastEntry = buckets[index]; + while (true) { - if (newEntry is null) + if (lastEntry.Key == newKey) { - resultingValue = value; - buckets[index] = new Entry(newKey, resultingValue, hash); + resultingValue = lastEntry.Value; + return false; } - else - { - resultingValue = newEntry.Value; - buckets[index] = newEntry; - } - } - else - { - var lastEntry = buckets[index]; - while (true) + + if (lastEntry.Next is null) { - if (lastEntry.Key == newKey) + if (newEntry is null) { - resultingValue = lastEntry.Value; - return false; + resultingValue = value; + lastEntry.Next = new Entry(newKey, resultingValue, hash); } - - if (lastEntry.Next is null) + else { - if (newEntry is null) - { - resultingValue = value; - lastEntry.Next = new Entry(newKey, resultingValue, hash); - } - else - { - resultingValue = newEntry.Value; - lastEntry.Next = newEntry; - } - break; + resultingValue = newEntry.Value; + lastEntry.Next = newEntry; } - - lastEntry = lastEntry.Next; + break; } + + lastEntry = lastEntry.Next; } - return true; } - #endregion + return true; } + #endregion + } - /// - /// Calculates bucket capacity. - /// - /// - /// - /// - private static int CalculateCapacity(int collectionSize, float loadFactor) - { - var initialCapacity = (int)(collectionSize / loadFactor); - var capacity = 1; - while (capacity < initialCapacity) - capacity <<= 1; + /// + /// Calculates bucket capacity. + /// + /// + /// + /// + private static int CalculateCapacity(int collectionSize, float loadFactor) + { + var initialCapacity = (int)(collectionSize / loadFactor); + var capacity = 1; + while (capacity < initialCapacity) + capacity <<= 1; - if (capacity < 8) - return 8; + if (capacity < 8) + return 8; - return capacity; - } - #endregion + return capacity; + } + #endregion - #region Get - /// - /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. - /// - /// - /// - /// - public TValue GetValueOrDefault(int key, TValue defaultValue = default) - => this.TryGetValue(key, out var value) - ? value - : defaultValue; - #endregion + #region Get + /// + /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. + /// + /// + /// + /// + public TValue GetValueOrDefault(int key, TValue defaultValue = default) + => this.TryGetValue(key, out var value) + ? value + : defaultValue; + #endregion + + + #region IReadOnlyDictionary implementations + /// + /// Gets the element that has the specified key in the read-only dictionary. + /// + /// The key to locate. + /// The element that has the specified key in the read-only dictionary. + public TValue this[int key] + => this.TryGetValue(key, out var value) + ? value + : throw new KeyNotFoundException(); + + + /// + /// Gets an enumerable collection that contains the keys in the read-only dictionary. + /// + public IEnumerable Keys + => throw new NotImplementedException(); + + + /// + /// Gets an enumerable collection that contains the values in the read-only dictionary. + /// + public IEnumerable Values + => throw new NotImplementedException(); + + + /// + /// Gets the number of elements in the collection. + /// + public int Count + => this.size; + + + /// + /// Determines whether the read-only dictionary contains an element that has the specified key. + /// + /// The key to locate. + /// + /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. + /// + public bool ContainsKey(int key) + => this.TryGetValue(key, out _); - #region IReadOnlyDictionary implementations - /// - /// Gets the element that has the specified key in the read-only dictionary. - /// - /// The key to locate. - /// The element that has the specified key in the read-only dictionary. - public TValue this[int key] - => this.TryGetValue(key, out var value) - ? value - : throw new KeyNotFoundException(); - - - /// - /// Gets an enumerable collection that contains the keys in the read-only dictionary. - /// - public IEnumerable Keys - => throw new NotImplementedException(); - - - /// - /// Gets an enumerable collection that contains the values in the read-only dictionary. - /// - public IEnumerable Values - => throw new NotImplementedException(); - - - /// - /// Gets the number of elements in the collection. - /// - public int Count - => this.size; - - - /// - /// Determines whether the read-only dictionary contains an element that has the specified key. - /// - /// The key to locate. - /// - /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. - /// - public bool ContainsKey(int key) - => this.TryGetValue(key, out _); - - - /// - /// Gets the value that is associated with the specified key. - /// - /// The key to locate. - /// - /// When this method returns, the value associated with the specified key, if the key is found; - /// otherwise, the default value for the type of the value parameter. - /// This parameter is passed uninitialized. - /// - /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetValue(int key, out TValue value) + /// + /// Gets the value that is associated with the specified key. + /// + /// The key to locate. + /// + /// When this method returns, the value associated with the specified key, if the key is found; + /// otherwise, the default value for the type of the value parameter. + /// This parameter is passed uninitialized. + /// + /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(int key, out TValue value) + { + var hash = key.GetHashCode(); + var index = hash & (this.buckets.Length - 1); + var next = this.buckets[index]; + while (next is not null) { - var hash = key.GetHashCode(); - var index = hash & (this.buckets.Length - 1); - var next = this.buckets[index]; - while (next is not null) + if (next.Key == key) { - if (next.Key == key) - { - value = next.Value; - return true; - } - next = next.Next; + value = next.Value; + return true; } - value = default; - return false; + next = next.Next; } + value = default; + return false; + } - /// - /// Returns an enumerator that iterates through the collection. - /// - /// An enumerator that can be used to iterate through the collection. - public IEnumerator> GetEnumerator() - => throw new NotImplementedException(); + /// + /// Returns an enumerator that iterates through the collection. + /// + /// An enumerator that can be used to iterate through the collection. + public IEnumerator> GetEnumerator() + => throw new NotImplementedException(); - /// - /// Returns an enumerator that iterates through a collection. - /// - /// An object that can be used to iterate through the collection. - IEnumerator IEnumerable.GetEnumerator() - => throw new NotImplementedException(); - #endregion + /// + /// Returns an enumerator that iterates through a collection. + /// + /// An object that can be used to iterate through the collection. + IEnumerator IEnumerable.GetEnumerator() + => throw new NotImplementedException(); + #endregion - #region Inner Classes - /// - /// Represents entry. - /// - private class Entry - { - public readonly int Key; - public readonly TValue Value; - public readonly int Hash; - public Entry Next; + #region Inner Classes + /// + /// Represents entry. + /// + private class Entry + { + public readonly int Key; + public readonly TValue Value; + public readonly int Hash; + public Entry Next; - public Entry(int key, TValue value, int hash) - { - this.Key = key; - this.Value = value; - this.Hash = hash; - } + public Entry(int key, TValue value, int hash) + { + this.Key = key; + this.Value = value; + this.Hash = hash; } - #endregion } + #endregion +} + +/// +/// Provides a read-only dictionary that contents are fixed at the time of instance creation. +/// +/// The type of values in the dictionary. +/// +/// Reference: +/// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs +/// +/// This class is uint specialized . +/// +internal sealed class FrozenUInt32KeyDictionary : IReadOnlyDictionary +{ + #region Constants + private static readonly Func PassThrough = x => x; + #endregion + + + #region Fields + private Entry[] buckets; + private int size; + private readonly float loadFactor; + #endregion + + #region Constructors /// - /// Provides a read-only dictionary that contents are fixed at the time of instance creation. + /// Creates instance. /// - /// The type of values in the dictionary. - /// - /// Reference: - /// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs - /// - /// This class is uint specialized . - /// - internal sealed class FrozenUInt32KeyDictionary : IReadOnlyDictionary + /// + /// + private FrozenUInt32KeyDictionary(int bucketSize, float loadFactor) { - #region Constants - private static readonly Func PassThrough = x => x; - #endregion + this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; + this.loadFactor = loadFactor; + } + #endregion - #region Fields - private Entry[] buckets; - private int size; - private readonly float loadFactor; - #endregion + #region Create + /// + /// Creates a from an according to a specified key selector function. + /// + /// + /// + /// + public static FrozenUInt32KeyDictionary Create(IEnumerable source, Func keySelector) + => Create(source, keySelector, PassThrough); + + /// + /// Creates a from an according to specified key selector and value selector functions. + /// + /// + /// + /// + /// + /// + public static FrozenUInt32KeyDictionary Create(IEnumerable source, Func keySelector, Func valueSelector) + { + const int initialSize = 4; + const float loadFactor = 0.75f; + var size = source.CountIfMaterialized() ?? initialSize; + var bucketSize = CalculateCapacity(size, loadFactor); + var result = new FrozenUInt32KeyDictionary(bucketSize, loadFactor); - #region Constructors - /// - /// Creates instance. - /// - /// - /// - private FrozenUInt32KeyDictionary(int bucketSize, float loadFactor) + foreach (var x in source) { - this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; - this.loadFactor = loadFactor; + var key = keySelector(x); + var value = valueSelector(x); + if (!result.TryAddInternal(key, value, out _)) + throw new ArgumentException($"Key was already exists. Key:{key}"); } - #endregion + return result; + } + #endregion - #region Create - /// - /// Creates a from an according to a specified key selector function. - /// - /// - /// - /// - public static FrozenUInt32KeyDictionary Create(IEnumerable source, Func keySelector) - => Create(source, keySelector, PassThrough); - - - /// - /// Creates a from an according to specified key selector and value selector functions. - /// - /// - /// - /// - /// - /// - public static FrozenUInt32KeyDictionary Create(IEnumerable source, Func keySelector, Func valueSelector) - { - const int initialSize = 4; - const float loadFactor = 0.75f; - var size = source.CountIfMaterialized() ?? initialSize; - var bucketSize = CalculateCapacity(size, loadFactor); - var result = new FrozenUInt32KeyDictionary(bucketSize, loadFactor); - foreach (var x in source) + #region Add + /// + /// Add element. + /// + /// + /// + /// + /// + private bool TryAddInternal(uint key, TValue value, out TValue resultingValue) + { + var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); + if (this.buckets.Length < nextCapacity) + { + //--- rehash + var nextBucket = new Entry[nextCapacity]; + for (int i = 0; i < this.buckets.Length; i++) { - var key = keySelector(x); - var value = valueSelector(x); - if (!result.TryAddInternal(key, value, out _)) - throw new ArgumentException($"Key was already exists. Key:{key}"); + var e = this.buckets[i]; + while (e is not null) + { + var newEntry = new Entry(e.Key, e.Value, e.Hash); + AddToBuckets(nextBucket, key, newEntry, default, out _); + e = e.Next; + } } - return result; + var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); + this.buckets = nextBucket; + if (success) + this.size++; + + return success; } - #endregion + else + { + var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); + if (success) + this.size++; + return success; + } - #region Add - /// - /// Add element. - /// - /// - /// - /// - /// - private bool TryAddInternal(uint key, TValue value, out TValue resultingValue) + #region Local Functions + //--- please pass 'key + newEntry' or 'key + value'. + static bool AddToBuckets(Entry[] buckets, uint newKey, Entry newEntry, TValue value, out TValue resultingValue) { - var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); - if (this.buckets.Length < nextCapacity) + var hash = newEntry?.Hash ?? newKey.GetHashCode(); + var index = hash & (buckets.Length - 1); + if (buckets[index] is null) { - //--- rehash - var nextBucket = new Entry[nextCapacity]; - for (int i = 0; i < this.buckets.Length; i++) + if (newEntry is null) { - var e = this.buckets[i]; - while (e is not null) - { - var newEntry = new Entry(e.Key, e.Value, e.Hash); - AddToBuckets(nextBucket, key, newEntry, default, out _); - e = e.Next; - } + resultingValue = value; + buckets[index] = new Entry(newKey, resultingValue, hash); + } + else + { + resultingValue = newEntry.Value; + buckets[index] = newEntry; } - - var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); - this.buckets = nextBucket; - if (success) - this.size++; - - return success; } else { - var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); - if (success) - this.size++; - - return success; - } - - #region Local Functions - //--- please pass 'key + newEntry' or 'key + value'. - static bool AddToBuckets(Entry[] buckets, uint newKey, Entry newEntry, TValue value, out TValue resultingValue) - { - var hash = newEntry?.Hash ?? newKey.GetHashCode(); - var index = hash & (buckets.Length - 1); - if (buckets[index] is null) + var lastEntry = buckets[index]; + while (true) { - if (newEntry is null) - { - resultingValue = value; - buckets[index] = new Entry(newKey, resultingValue, hash); - } - else + if (lastEntry.Key == newKey) { - resultingValue = newEntry.Value; - buckets[index] = newEntry; + resultingValue = lastEntry.Value; + return false; } - } - else - { - var lastEntry = buckets[index]; - while (true) + + if (lastEntry.Next is null) { - if (lastEntry.Key == newKey) + if (newEntry is null) { - resultingValue = lastEntry.Value; - return false; + resultingValue = value; + lastEntry.Next = new Entry(newKey, resultingValue, hash); } - - if (lastEntry.Next is null) + else { - if (newEntry is null) - { - resultingValue = value; - lastEntry.Next = new Entry(newKey, resultingValue, hash); - } - else - { - resultingValue = newEntry.Value; - lastEntry.Next = newEntry; - } - break; + resultingValue = newEntry.Value; + lastEntry.Next = newEntry; } - - lastEntry = lastEntry.Next; + break; } + + lastEntry = lastEntry.Next; } - return true; } - #endregion + return true; } + #endregion + } - /// - /// Calculates bucket capacity. - /// - /// - /// - /// - private static int CalculateCapacity(int collectionSize, float loadFactor) - { - var initialCapacity = (int)(collectionSize / loadFactor); - var capacity = 1; - while (capacity < initialCapacity) - capacity <<= 1; + /// + /// Calculates bucket capacity. + /// + /// + /// + /// + private static int CalculateCapacity(int collectionSize, float loadFactor) + { + var initialCapacity = (int)(collectionSize / loadFactor); + var capacity = 1; + while (capacity < initialCapacity) + capacity <<= 1; - if (capacity < 8) - return 8; + if (capacity < 8) + return 8; - return capacity; - } - #endregion + return capacity; + } + #endregion - #region Get - /// - /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. - /// - /// - /// - /// - public TValue GetValueOrDefault(uint key, TValue defaultValue = default) - => this.TryGetValue(key, out var value) - ? value - : defaultValue; - #endregion + #region Get + /// + /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. + /// + /// + /// + /// + public TValue GetValueOrDefault(uint key, TValue defaultValue = default) + => this.TryGetValue(key, out var value) + ? value + : defaultValue; + #endregion + + + #region IReadOnlyDictionary implementations + /// + /// Gets the element that has the specified key in the read-only dictionary. + /// + /// The key to locate. + /// The element that has the specified key in the read-only dictionary. + public TValue this[uint key] + => this.TryGetValue(key, out var value) + ? value + : throw new KeyNotFoundException(); + + /// + /// Gets an enumerable collection that contains the keys in the read-only dictionary. + /// + public IEnumerable Keys + => throw new NotImplementedException(); + + + /// + /// Gets an enumerable collection that contains the values in the read-only dictionary. + /// + public IEnumerable Values + => throw new NotImplementedException(); + + + /// + /// Gets the number of elements in the collection. + /// + public int Count + => this.size; + + + /// + /// Determines whether the read-only dictionary contains an element that has the specified key. + /// + /// The key to locate. + /// + /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. + /// + public bool ContainsKey(uint key) + => this.TryGetValue(key, out _); - #region IReadOnlyDictionary implementations - /// - /// Gets the element that has the specified key in the read-only dictionary. - /// - /// The key to locate. - /// The element that has the specified key in the read-only dictionary. - public TValue this[uint key] - => this.TryGetValue(key, out var value) - ? value - : throw new KeyNotFoundException(); - - - /// - /// Gets an enumerable collection that contains the keys in the read-only dictionary. - /// - public IEnumerable Keys - => throw new NotImplementedException(); - - - /// - /// Gets an enumerable collection that contains the values in the read-only dictionary. - /// - public IEnumerable Values - => throw new NotImplementedException(); - - - /// - /// Gets the number of elements in the collection. - /// - public int Count - => this.size; - - - /// - /// Determines whether the read-only dictionary contains an element that has the specified key. - /// - /// The key to locate. - /// - /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. - /// - public bool ContainsKey(uint key) - => this.TryGetValue(key, out _); - - - /// - /// Gets the value that is associated with the specified key. - /// - /// The key to locate. - /// - /// When this method returns, the value associated with the specified key, if the key is found; - /// otherwise, the default value for the type of the value parameter. - /// This parameter is passed uninitialized. - /// - /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetValue(uint key, out TValue value) + + /// + /// Gets the value that is associated with the specified key. + /// + /// The key to locate. + /// + /// When this method returns, the value associated with the specified key, if the key is found; + /// otherwise, the default value for the type of the value parameter. + /// This parameter is passed uninitialized. + /// + /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(uint key, out TValue value) + { + var hash = key.GetHashCode(); + var index = hash & (this.buckets.Length - 1); + var next = this.buckets[index]; + while (next is not null) { - var hash = key.GetHashCode(); - var index = hash & (this.buckets.Length - 1); - var next = this.buckets[index]; - while (next is not null) + if (next.Key == key) { - if (next.Key == key) - { - value = next.Value; - return true; - } - next = next.Next; + value = next.Value; + return true; } - value = default; - return false; + next = next.Next; } + value = default; + return false; + } - /// - /// Returns an enumerator that iterates through the collection. - /// - /// An enumerator that can be used to iterate through the collection. - public IEnumerator> GetEnumerator() - => throw new NotImplementedException(); + /// + /// Returns an enumerator that iterates through the collection. + /// + /// An enumerator that can be used to iterate through the collection. + public IEnumerator> GetEnumerator() + => throw new NotImplementedException(); - /// - /// Returns an enumerator that iterates through a collection. - /// - /// An object that can be used to iterate through the collection. - IEnumerator IEnumerable.GetEnumerator() - => throw new NotImplementedException(); - #endregion + /// + /// Returns an enumerator that iterates through a collection. + /// + /// An object that can be used to iterate through the collection. + IEnumerator IEnumerable.GetEnumerator() + => throw new NotImplementedException(); + #endregion - #region Inner Classes - /// - /// Represents entry. - /// - private class Entry - { - public readonly uint Key; - public readonly TValue Value; - public readonly int Hash; - public Entry Next; + #region Inner Classes + /// + /// Represents entry. + /// + private class Entry + { + public readonly uint Key; + public readonly TValue Value; + public readonly int Hash; + public Entry Next; - public Entry(uint key, TValue value, int hash) - { - this.Key = key; - this.Value = value; - this.Hash = hash; - } + public Entry(uint key, TValue value, int hash) + { + this.Key = key; + this.Value = value; + this.Hash = hash; } - #endregion } + #endregion +} + + + +/// +/// Provides a read-only dictionary that contents are fixed at the time of instance creation. +/// +/// The type of values in the dictionary. +/// +/// Reference: +/// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs +/// +/// This class is long specialized . +/// +internal sealed class FrozenInt64KeyDictionary : IReadOnlyDictionary +{ + #region Constants + private static readonly Func PassThrough = x => x; + #endregion + #region Fields + private Entry[] buckets; + private int size; + private readonly float loadFactor; + #endregion + + #region Constructors /// - /// Provides a read-only dictionary that contents are fixed at the time of instance creation. + /// Creates instance. /// - /// The type of values in the dictionary. - /// - /// Reference: - /// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs - /// - /// This class is long specialized . - /// - internal sealed class FrozenInt64KeyDictionary : IReadOnlyDictionary + /// + /// + private FrozenInt64KeyDictionary(int bucketSize, float loadFactor) { - #region Constants - private static readonly Func PassThrough = x => x; - #endregion + this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; + this.loadFactor = loadFactor; + } + #endregion - #region Fields - private Entry[] buckets; - private int size; - private readonly float loadFactor; - #endregion + #region Create + /// + /// Creates a from an according to a specified key selector function. + /// + /// + /// + /// + public static FrozenInt64KeyDictionary Create(IEnumerable source, Func keySelector) + => Create(source, keySelector, PassThrough); - #region Constructors - /// - /// Creates instance. - /// - /// - /// - private FrozenInt64KeyDictionary(int bucketSize, float loadFactor) + /// + /// Creates a from an according to specified key selector and value selector functions. + /// + /// + /// + /// + /// + /// + public static FrozenInt64KeyDictionary Create(IEnumerable source, Func keySelector, Func valueSelector) + { + const int initialSize = 4; + const float loadFactor = 0.75f; + var size = source.CountIfMaterialized() ?? initialSize; + var bucketSize = CalculateCapacity(size, loadFactor); + var result = new FrozenInt64KeyDictionary(bucketSize, loadFactor); + + foreach (var x in source) { - this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; - this.loadFactor = loadFactor; + var key = keySelector(x); + var value = valueSelector(x); + if (!result.TryAddInternal(key, value, out _)) + throw new ArgumentException($"Key was already exists. Key:{key}"); } - #endregion + return result; + } + #endregion - #region Create - /// - /// Creates a from an according to a specified key selector function. - /// - /// - /// - /// - public static FrozenInt64KeyDictionary Create(IEnumerable source, Func keySelector) - => Create(source, keySelector, PassThrough); - - - /// - /// Creates a from an according to specified key selector and value selector functions. - /// - /// - /// - /// - /// - /// - public static FrozenInt64KeyDictionary Create(IEnumerable source, Func keySelector, Func valueSelector) - { - const int initialSize = 4; - const float loadFactor = 0.75f; - var size = source.CountIfMaterialized() ?? initialSize; - var bucketSize = CalculateCapacity(size, loadFactor); - var result = new FrozenInt64KeyDictionary(bucketSize, loadFactor); - foreach (var x in source) + #region Add + /// + /// Add element. + /// + /// + /// + /// + /// + private bool TryAddInternal(long key, TValue value, out TValue resultingValue) + { + var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); + if (this.buckets.Length < nextCapacity) + { + //--- rehash + var nextBucket = new Entry[nextCapacity]; + for (int i = 0; i < this.buckets.Length; i++) { - var key = keySelector(x); - var value = valueSelector(x); - if (!result.TryAddInternal(key, value, out _)) - throw new ArgumentException($"Key was already exists. Key:{key}"); + var e = this.buckets[i]; + while (e is not null) + { + var newEntry = new Entry(e.Key, e.Value, e.Hash); + AddToBuckets(nextBucket, key, newEntry, default, out _); + e = e.Next; + } } - return result; + var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); + this.buckets = nextBucket; + if (success) + this.size++; + + return success; } - #endregion + else + { + var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); + if (success) + this.size++; + return success; + } - #region Add - /// - /// Add element. - /// - /// - /// - /// - /// - private bool TryAddInternal(long key, TValue value, out TValue resultingValue) + #region Local Functions + //--- please pass 'key + newEntry' or 'key + value'. + static bool AddToBuckets(Entry[] buckets, long newKey, Entry newEntry, TValue value, out TValue resultingValue) { - var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); - if (this.buckets.Length < nextCapacity) + var hash = newEntry?.Hash ?? newKey.GetHashCode(); + var index = hash & (buckets.Length - 1); + if (buckets[index] is null) { - //--- rehash - var nextBucket = new Entry[nextCapacity]; - for (int i = 0; i < this.buckets.Length; i++) + if (newEntry is null) { - var e = this.buckets[i]; - while (e is not null) - { - var newEntry = new Entry(e.Key, e.Value, e.Hash); - AddToBuckets(nextBucket, key, newEntry, default, out _); - e = e.Next; - } + resultingValue = value; + buckets[index] = new Entry(newKey, resultingValue, hash); + } + else + { + resultingValue = newEntry.Value; + buckets[index] = newEntry; } - - var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); - this.buckets = nextBucket; - if (success) - this.size++; - - return success; } else { - var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); - if (success) - this.size++; - - return success; - } - - #region Local Functions - //--- please pass 'key + newEntry' or 'key + value'. - static bool AddToBuckets(Entry[] buckets, long newKey, Entry newEntry, TValue value, out TValue resultingValue) - { - var hash = newEntry?.Hash ?? newKey.GetHashCode(); - var index = hash & (buckets.Length - 1); - if (buckets[index] is null) + var lastEntry = buckets[index]; + while (true) { - if (newEntry is null) - { - resultingValue = value; - buckets[index] = new Entry(newKey, resultingValue, hash); - } - else + if (lastEntry.Key == newKey) { - resultingValue = newEntry.Value; - buckets[index] = newEntry; + resultingValue = lastEntry.Value; + return false; } - } - else - { - var lastEntry = buckets[index]; - while (true) + + if (lastEntry.Next is null) { - if (lastEntry.Key == newKey) + if (newEntry is null) { - resultingValue = lastEntry.Value; - return false; + resultingValue = value; + lastEntry.Next = new Entry(newKey, resultingValue, hash); } - - if (lastEntry.Next is null) + else { - if (newEntry is null) - { - resultingValue = value; - lastEntry.Next = new Entry(newKey, resultingValue, hash); - } - else - { - resultingValue = newEntry.Value; - lastEntry.Next = newEntry; - } - break; + resultingValue = newEntry.Value; + lastEntry.Next = newEntry; } - - lastEntry = lastEntry.Next; + break; } + + lastEntry = lastEntry.Next; } - return true; } - #endregion + return true; } + #endregion + } - /// - /// Calculates bucket capacity. - /// - /// - /// - /// - private static int CalculateCapacity(int collectionSize, float loadFactor) - { - var initialCapacity = (int)(collectionSize / loadFactor); - var capacity = 1; - while (capacity < initialCapacity) - capacity <<= 1; + /// + /// Calculates bucket capacity. + /// + /// + /// + /// + private static int CalculateCapacity(int collectionSize, float loadFactor) + { + var initialCapacity = (int)(collectionSize / loadFactor); + var capacity = 1; + while (capacity < initialCapacity) + capacity <<= 1; - if (capacity < 8) - return 8; + if (capacity < 8) + return 8; - return capacity; - } - #endregion + return capacity; + } + #endregion - #region Get - /// - /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. - /// - /// - /// - /// - public TValue GetValueOrDefault(long key, TValue defaultValue = default) - => this.TryGetValue(key, out var value) - ? value - : defaultValue; - #endregion + #region Get + /// + /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. + /// + /// + /// + /// + public TValue GetValueOrDefault(long key, TValue defaultValue = default) + => this.TryGetValue(key, out var value) + ? value + : defaultValue; + #endregion + + + #region IReadOnlyDictionary implementations + /// + /// Gets the element that has the specified key in the read-only dictionary. + /// + /// The key to locate. + /// The element that has the specified key in the read-only dictionary. + public TValue this[long key] + => this.TryGetValue(key, out var value) + ? value + : throw new KeyNotFoundException(); + + + /// + /// Gets an enumerable collection that contains the keys in the read-only dictionary. + /// + public IEnumerable Keys + => throw new NotImplementedException(); + + + /// + /// Gets an enumerable collection that contains the values in the read-only dictionary. + /// + public IEnumerable Values + => throw new NotImplementedException(); + + + /// + /// Gets the number of elements in the collection. + /// + public int Count + => this.size; - #region IReadOnlyDictionary implementations - /// - /// Gets the element that has the specified key in the read-only dictionary. - /// - /// The key to locate. - /// The element that has the specified key in the read-only dictionary. - public TValue this[long key] - => this.TryGetValue(key, out var value) - ? value - : throw new KeyNotFoundException(); - - - /// - /// Gets an enumerable collection that contains the keys in the read-only dictionary. - /// - public IEnumerable Keys - => throw new NotImplementedException(); - - - /// - /// Gets an enumerable collection that contains the values in the read-only dictionary. - /// - public IEnumerable Values - => throw new NotImplementedException(); - - - /// - /// Gets the number of elements in the collection. - /// - public int Count - => this.size; - - - /// - /// Determines whether the read-only dictionary contains an element that has the specified key. - /// - /// The key to locate. - /// - /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. - /// - public bool ContainsKey(long key) - => this.TryGetValue(key, out _); - - - /// - /// Gets the value that is associated with the specified key. - /// - /// The key to locate. - /// - /// When this method returns, the value associated with the specified key, if the key is found; - /// otherwise, the default value for the type of the value parameter. - /// This parameter is passed uninitialized. - /// - /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetValue(long key, out TValue value) + /// + /// Determines whether the read-only dictionary contains an element that has the specified key. + /// + /// The key to locate. + /// + /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. + /// + public bool ContainsKey(long key) + => this.TryGetValue(key, out _); + + + /// + /// Gets the value that is associated with the specified key. + /// + /// The key to locate. + /// + /// When this method returns, the value associated with the specified key, if the key is found; + /// otherwise, the default value for the type of the value parameter. + /// This parameter is passed uninitialized. + /// + /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(long key, out TValue value) + { + var hash = key.GetHashCode(); + var index = hash & (this.buckets.Length - 1); + var next = this.buckets[index]; + while (next is not null) { - var hash = key.GetHashCode(); - var index = hash & (this.buckets.Length - 1); - var next = this.buckets[index]; - while (next is not null) + if (next.Key == key) { - if (next.Key == key) - { - value = next.Value; - return true; - } - next = next.Next; + value = next.Value; + return true; } - value = default; - return false; + next = next.Next; } + value = default; + return false; + } - /// - /// Returns an enumerator that iterates through the collection. - /// - /// An enumerator that can be used to iterate through the collection. - public IEnumerator> GetEnumerator() - => throw new NotImplementedException(); + /// + /// Returns an enumerator that iterates through the collection. + /// + /// An enumerator that can be used to iterate through the collection. + public IEnumerator> GetEnumerator() + => throw new NotImplementedException(); - /// - /// Returns an enumerator that iterates through a collection. - /// - /// An object that can be used to iterate through the collection. - IEnumerator IEnumerable.GetEnumerator() - => throw new NotImplementedException(); - #endregion + /// + /// Returns an enumerator that iterates through a collection. + /// + /// An object that can be used to iterate through the collection. + IEnumerator IEnumerable.GetEnumerator() + => throw new NotImplementedException(); + #endregion - #region Inner Classes - /// - /// Represents entry. - /// - private class Entry - { - public readonly long Key; - public readonly TValue Value; - public readonly int Hash; - public Entry Next; + #region Inner Classes + /// + /// Represents entry. + /// + private class Entry + { + public readonly long Key; + public readonly TValue Value; + public readonly int Hash; + public Entry Next; - public Entry(long key, TValue value, int hash) - { - this.Key = key; - this.Value = value; - this.Hash = hash; - } + public Entry(long key, TValue value, int hash) + { + this.Key = key; + this.Value = value; + this.Hash = hash; } - #endregion } + #endregion +} + + + +/// +/// Provides a read-only dictionary that contents are fixed at the time of instance creation. +/// +/// The type of values in the dictionary. +/// +/// Reference: +/// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs +/// +/// This class is ulong specialized . +/// +internal sealed class FrozenUInt64KeyDictionary : IReadOnlyDictionary +{ + #region Constants + private static readonly Func PassThrough = x => x; + #endregion + + #region Fields + private Entry[] buckets; + private int size; + private readonly float loadFactor; + #endregion + #region Constructors /// - /// Provides a read-only dictionary that contents are fixed at the time of instance creation. + /// Creates instance. /// - /// The type of values in the dictionary. - /// - /// Reference: - /// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs - /// - /// This class is ulong specialized . - /// - internal sealed class FrozenUInt64KeyDictionary : IReadOnlyDictionary + /// + /// + private FrozenUInt64KeyDictionary(int bucketSize, float loadFactor) { - #region Constants - private static readonly Func PassThrough = x => x; - #endregion + this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; + this.loadFactor = loadFactor; + } + #endregion - #region Fields - private Entry[] buckets; - private int size; - private readonly float loadFactor; - #endregion + #region Create + /// + /// Creates a from an according to a specified key selector function. + /// + /// + /// + /// + public static FrozenUInt64KeyDictionary Create(IEnumerable source, Func keySelector) + => Create(source, keySelector, PassThrough); + + /// + /// Creates a from an according to specified key selector and value selector functions. + /// + /// + /// + /// + /// + /// + public static FrozenUInt64KeyDictionary Create(IEnumerable source, Func keySelector, Func valueSelector) + { + const int initialSize = 4; + const float loadFactor = 0.75f; + var size = source.CountIfMaterialized() ?? initialSize; + var bucketSize = CalculateCapacity(size, loadFactor); + var result = new FrozenUInt64KeyDictionary(bucketSize, loadFactor); - #region Constructors - /// - /// Creates instance. - /// - /// - /// - private FrozenUInt64KeyDictionary(int bucketSize, float loadFactor) + foreach (var x in source) { - this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; - this.loadFactor = loadFactor; + var key = keySelector(x); + var value = valueSelector(x); + if (!result.TryAddInternal(key, value, out _)) + throw new ArgumentException($"Key was already exists. Key:{key}"); } - #endregion + return result; + } + #endregion - #region Create - /// - /// Creates a from an according to a specified key selector function. - /// - /// - /// - /// - public static FrozenUInt64KeyDictionary Create(IEnumerable source, Func keySelector) - => Create(source, keySelector, PassThrough); - - - /// - /// Creates a from an according to specified key selector and value selector functions. - /// - /// - /// - /// - /// - /// - public static FrozenUInt64KeyDictionary Create(IEnumerable source, Func keySelector, Func valueSelector) - { - const int initialSize = 4; - const float loadFactor = 0.75f; - var size = source.CountIfMaterialized() ?? initialSize; - var bucketSize = CalculateCapacity(size, loadFactor); - var result = new FrozenUInt64KeyDictionary(bucketSize, loadFactor); - foreach (var x in source) + #region Add + /// + /// Add element. + /// + /// + /// + /// + /// + private bool TryAddInternal(ulong key, TValue value, out TValue resultingValue) + { + var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); + if (this.buckets.Length < nextCapacity) + { + //--- rehash + var nextBucket = new Entry[nextCapacity]; + for (int i = 0; i < this.buckets.Length; i++) { - var key = keySelector(x); - var value = valueSelector(x); - if (!result.TryAddInternal(key, value, out _)) - throw new ArgumentException($"Key was already exists. Key:{key}"); + var e = this.buckets[i]; + while (e is not null) + { + var newEntry = new Entry(e.Key, e.Value, e.Hash); + AddToBuckets(nextBucket, key, newEntry, default, out _); + e = e.Next; + } } - return result; + var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); + this.buckets = nextBucket; + if (success) + this.size++; + + return success; } - #endregion + else + { + var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); + if (success) + this.size++; + return success; + } - #region Add - /// - /// Add element. - /// - /// - /// - /// - /// - private bool TryAddInternal(ulong key, TValue value, out TValue resultingValue) + #region Local Functions + //--- please pass 'key + newEntry' or 'key + value'. + static bool AddToBuckets(Entry[] buckets, ulong newKey, Entry newEntry, TValue value, out TValue resultingValue) { - var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); - if (this.buckets.Length < nextCapacity) + var hash = newEntry?.Hash ?? newKey.GetHashCode(); + var index = hash & (buckets.Length - 1); + if (buckets[index] is null) { - //--- rehash - var nextBucket = new Entry[nextCapacity]; - for (int i = 0; i < this.buckets.Length; i++) + if (newEntry is null) { - var e = this.buckets[i]; - while (e is not null) - { - var newEntry = new Entry(e.Key, e.Value, e.Hash); - AddToBuckets(nextBucket, key, newEntry, default, out _); - e = e.Next; - } + resultingValue = value; + buckets[index] = new Entry(newKey, resultingValue, hash); + } + else + { + resultingValue = newEntry.Value; + buckets[index] = newEntry; } - - var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); - this.buckets = nextBucket; - if (success) - this.size++; - - return success; } else { - var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); - if (success) - this.size++; - - return success; - } - - #region Local Functions - //--- please pass 'key + newEntry' or 'key + value'. - static bool AddToBuckets(Entry[] buckets, ulong newKey, Entry newEntry, TValue value, out TValue resultingValue) - { - var hash = newEntry?.Hash ?? newKey.GetHashCode(); - var index = hash & (buckets.Length - 1); - if (buckets[index] is null) + var lastEntry = buckets[index]; + while (true) { - if (newEntry is null) + if (lastEntry.Key == newKey) { - resultingValue = value; - buckets[index] = new Entry(newKey, resultingValue, hash); + resultingValue = lastEntry.Value; + return false; } - else - { - resultingValue = newEntry.Value; - buckets[index] = newEntry; - } - } - else - { - var lastEntry = buckets[index]; - while (true) + + if (lastEntry.Next is null) { - if (lastEntry.Key == newKey) + if (newEntry is null) { - resultingValue = lastEntry.Value; - return false; + resultingValue = value; + lastEntry.Next = new Entry(newKey, resultingValue, hash); } - - if (lastEntry.Next is null) + else { - if (newEntry is null) - { - resultingValue = value; - lastEntry.Next = new Entry(newKey, resultingValue, hash); - } - else - { - resultingValue = newEntry.Value; - lastEntry.Next = newEntry; - } - break; + resultingValue = newEntry.Value; + lastEntry.Next = newEntry; } - - lastEntry = lastEntry.Next; + break; } + + lastEntry = lastEntry.Next; } - return true; } - #endregion + return true; } + #endregion + } - /// - /// Calculates bucket capacity. - /// - /// - /// - /// - private static int CalculateCapacity(int collectionSize, float loadFactor) - { - var initialCapacity = (int)(collectionSize / loadFactor); - var capacity = 1; - while (capacity < initialCapacity) - capacity <<= 1; + /// + /// Calculates bucket capacity. + /// + /// + /// + /// + private static int CalculateCapacity(int collectionSize, float loadFactor) + { + var initialCapacity = (int)(collectionSize / loadFactor); + var capacity = 1; + while (capacity < initialCapacity) + capacity <<= 1; - if (capacity < 8) - return 8; + if (capacity < 8) + return 8; - return capacity; - } - #endregion + return capacity; + } + #endregion - #region Get - /// - /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. - /// - /// - /// - /// - public TValue GetValueOrDefault(ulong key, TValue defaultValue = default) - => this.TryGetValue(key, out var value) - ? value - : defaultValue; - #endregion + #region Get + /// + /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. + /// + /// + /// + /// + public TValue GetValueOrDefault(ulong key, TValue defaultValue = default) + => this.TryGetValue(key, out var value) + ? value + : defaultValue; + #endregion + + + #region IReadOnlyDictionary implementations + /// + /// Gets the element that has the specified key in the read-only dictionary. + /// + /// The key to locate. + /// The element that has the specified key in the read-only dictionary. + public TValue this[ulong key] + => this.TryGetValue(key, out var value) + ? value + : throw new KeyNotFoundException(); + + + /// + /// Gets an enumerable collection that contains the keys in the read-only dictionary. + /// + public IEnumerable Keys + => throw new NotImplementedException(); + + /// + /// Gets an enumerable collection that contains the values in the read-only dictionary. + /// + public IEnumerable Values + => throw new NotImplementedException(); - #region IReadOnlyDictionary implementations - /// - /// Gets the element that has the specified key in the read-only dictionary. - /// - /// The key to locate. - /// The element that has the specified key in the read-only dictionary. - public TValue this[ulong key] - => this.TryGetValue(key, out var value) - ? value - : throw new KeyNotFoundException(); - - - /// - /// Gets an enumerable collection that contains the keys in the read-only dictionary. - /// - public IEnumerable Keys - => throw new NotImplementedException(); - - - /// - /// Gets an enumerable collection that contains the values in the read-only dictionary. - /// - public IEnumerable Values - => throw new NotImplementedException(); - - - /// - /// Gets the number of elements in the collection. - /// - public int Count - => this.size; - - - /// - /// Determines whether the read-only dictionary contains an element that has the specified key. - /// - /// The key to locate. - /// - /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. - /// - public bool ContainsKey(ulong key) - => this.TryGetValue(key, out _); - - - /// - /// Gets the value that is associated with the specified key. - /// - /// The key to locate. - /// - /// When this method returns, the value associated with the specified key, if the key is found; - /// otherwise, the default value for the type of the value parameter. - /// This parameter is passed uninitialized. - /// - /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetValue(ulong key, out TValue value) + + /// + /// Gets the number of elements in the collection. + /// + public int Count + => this.size; + + + /// + /// Determines whether the read-only dictionary contains an element that has the specified key. + /// + /// The key to locate. + /// + /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. + /// + public bool ContainsKey(ulong key) + => this.TryGetValue(key, out _); + + + /// + /// Gets the value that is associated with the specified key. + /// + /// The key to locate. + /// + /// When this method returns, the value associated with the specified key, if the key is found; + /// otherwise, the default value for the type of the value parameter. + /// This parameter is passed uninitialized. + /// + /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(ulong key, out TValue value) + { + var hash = key.GetHashCode(); + var index = hash & (this.buckets.Length - 1); + var next = this.buckets[index]; + while (next is not null) { - var hash = key.GetHashCode(); - var index = hash & (this.buckets.Length - 1); - var next = this.buckets[index]; - while (next is not null) + if (next.Key == key) { - if (next.Key == key) - { - value = next.Value; - return true; - } - next = next.Next; + value = next.Value; + return true; } - value = default; - return false; + next = next.Next; } + value = default; + return false; + } - /// - /// Returns an enumerator that iterates through the collection. - /// - /// An enumerator that can be used to iterate through the collection. - public IEnumerator> GetEnumerator() - => throw new NotImplementedException(); + /// + /// Returns an enumerator that iterates through the collection. + /// + /// An enumerator that can be used to iterate through the collection. + public IEnumerator> GetEnumerator() + => throw new NotImplementedException(); - /// - /// Returns an enumerator that iterates through a collection. - /// - /// An object that can be used to iterate through the collection. - IEnumerator IEnumerable.GetEnumerator() - => throw new NotImplementedException(); - #endregion + /// + /// Returns an enumerator that iterates through a collection. + /// + /// An object that can be used to iterate through the collection. + IEnumerator IEnumerable.GetEnumerator() + => throw new NotImplementedException(); + #endregion - #region Inner Classes - /// - /// Represents entry. - /// - private class Entry - { - public readonly ulong Key; - public readonly TValue Value; - public readonly int Hash; - public Entry Next; + #region Inner Classes + /// + /// Represents entry. + /// + private class Entry + { + public readonly ulong Key; + public readonly TValue Value; + public readonly int Hash; + public Entry Next; - public Entry(ulong key, TValue value, int hash) - { - this.Key = key; - this.Value = value; - this.Hash = hash; - } + public Entry(ulong key, TValue value, int hash) + { + this.Key = key; + this.Value = value; + this.Hash = hash; } - #endregion } + #endregion +} -} diff --git a/src/DeclarativeSql/Internals/FrozenDictionary.tt b/src/DeclarativeSql/Internals/FrozenDictionary.tt index bdc56e6..39b5acc 100644 --- a/src/DeclarativeSql/Internals/FrozenDictionary.tt +++ b/src/DeclarativeSql/Internals/FrozenDictionary.tt @@ -46,354 +46,353 @@ using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; +namespace DeclarativeSql.Internals; + -namespace DeclarativeSql.Internals -{ <# foreach (var x in parameters) { #> - /// - /// Provides a read-only dictionary that contents are fixed at the time of instance creation. - /// +/// +/// Provides a read-only dictionary that contents are fixed at the time of instance creation. +/// <# if (!x.IsSpecialized) { #> - /// The type of keys in the dictionary. +/// The type of keys in the dictionary. <# } #> - /// The type of values in the dictionary. - /// - /// Reference: - /// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs +/// The type of values in the dictionary. +/// +/// Reference: +/// https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/ThreadsafeTypeKeyHashTable.cs <# if (x.IsSpecialized) { #> - /// - /// This class is <#= x.CompatibleName #> specialized . +/// +/// This class is <#= x.CompatibleName #> specialized . <# } #> - /// - internal sealed class <#= GetClass(x.TypeName) #> : IReadOnlyDictionary<<#= x.CompatibleName #>, TValue> - { - #region Constants - private static readonly Func PassThrough = x => x; - #endregion +/// +internal sealed class <#= GetClass(x.TypeName) #> : IReadOnlyDictionary<<#= x.CompatibleName #>, TValue> +{ + #region Constants + private static readonly Func PassThrough = x => x; + #endregion - #region Fields - private Entry[] buckets; - private int size; - private readonly float loadFactor; - #endregion + #region Fields + private Entry[] buckets; + private int size; + private readonly float loadFactor; + #endregion - #region Constructors - /// - /// Creates instance. - /// - /// - /// - private <#= GetCtor(x.TypeName) #>(int bucketSize, float loadFactor) - { - this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; - this.loadFactor = loadFactor; - } - #endregion + #region Constructors + /// + /// Creates instance. + /// + /// + /// + private <#= GetCtor(x.TypeName) #>(int bucketSize, float loadFactor) + { + this.buckets = (bucketSize == 0) ? Array.Empty() : new Entry[bucketSize]; + this.loadFactor = loadFactor; + } + #endregion - #region Create - /// - /// Creates a from an according to a specified key selector function. - /// - /// - /// - /// - public static <#= GetClass(x.TypeName) #> Create(IEnumerable source, Func> keySelector) - => Create(source, keySelector, PassThrough); - - - /// - /// Creates a from an according to specified key selector and value selector functions. - /// - /// - /// - /// - /// - /// - public static <#= GetClass(x.TypeName) #> Create(IEnumerable source, Func> keySelector, Func valueSelector) - { - const int initialSize = 4; - const float loadFactor = 0.75f; - var size = source.CountIfMaterialized() ?? initialSize; - var bucketSize = CalculateCapacity(size, loadFactor); - var result = new <#= GetClass(x.TypeName) #>(bucketSize, loadFactor); + #region Create + /// + /// Creates a from an according to a specified key selector function. + /// + /// + /// + /// + public static <#= GetClass(x.TypeName) #> Create(IEnumerable source, Func> keySelector) + => Create(source, keySelector, PassThrough); - foreach (var x in source) - { - var key = keySelector(x); - var value = valueSelector(x); - if (!result.TryAddInternal(key, value, out _)) - throw new ArgumentException($"Key was already exists. Key:{key}"); - } - return result; + /// + /// Creates a from an according to specified key selector and value selector functions. + /// + /// + /// + /// + /// + /// + public static <#= GetClass(x.TypeName) #> Create(IEnumerable source, Func> keySelector, Func valueSelector) + { + const int initialSize = 4; + const float loadFactor = 0.75f; + var size = source.CountIfMaterialized() ?? initialSize; + var bucketSize = CalculateCapacity(size, loadFactor); + var result = new <#= GetClass(x.TypeName) #>(bucketSize, loadFactor); + + foreach (var x in source) + { + var key = keySelector(x); + var value = valueSelector(x); + if (!result.TryAddInternal(key, value, out _)) + throw new ArgumentException($"Key was already exists. Key:{key}"); } - #endregion + return result; + } + #endregion - #region Add - /// - /// Add element. - /// - /// - /// - /// - /// - private bool TryAddInternal(<#= x.CompatibleName #> key, TValue value, out TValue resultingValue) + + #region Add + /// + /// Add element. + /// + /// + /// + /// + /// + private bool TryAddInternal(<#= x.CompatibleName #> key, TValue value, out TValue resultingValue) + { + var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); + if (this.buckets.Length < nextCapacity) { - var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor); - if (this.buckets.Length < nextCapacity) + //--- rehash + var nextBucket = new Entry[nextCapacity]; + for (int i = 0; i < this.buckets.Length; i++) { - //--- rehash - var nextBucket = new Entry[nextCapacity]; - for (int i = 0; i < this.buckets.Length; i++) + var e = this.buckets[i]; + while (e is not null) { - var e = this.buckets[i]; - while (e is not null) - { - var newEntry = new Entry(e.Key, e.Value, e.Hash); - AddToBuckets(nextBucket, key, newEntry, default, out _); - e = e.Next; - } + var newEntry = new Entry(e.Key, e.Value, e.Hash); + AddToBuckets(nextBucket, key, newEntry, default, out _); + e = e.Next; } + } - var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); - this.buckets = nextBucket; - if (success) - this.size++; + var success = AddToBuckets(nextBucket, key, null, value, out resultingValue); + this.buckets = nextBucket; + if (success) + this.size++; - return success; - } - else - { - var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); - if (success) - this.size++; + return success; + } + else + { + var success = AddToBuckets(this.buckets, key, null, value, out resultingValue); + if (success) + this.size++; - return success; - } + return success; + } - #region Local Functions - //--- please pass 'key + newEntry' or 'key + value'. - static bool AddToBuckets(Entry[] buckets, <#= x.CompatibleName #> newKey, Entry newEntry, TValue value, out TValue resultingValue) - { + #region Local Functions + //--- please pass 'key + newEntry' or 'key + value'. + static bool AddToBuckets(Entry[] buckets, <#= x.CompatibleName #> newKey, Entry newEntry, TValue value, out TValue resultingValue) + { <# if (x.IsSpecialized) { #> - var hash = newEntry?.Hash ?? newKey.GetHashCode(); + var hash = newEntry?.Hash ?? newKey.GetHashCode(); <# } else { #> - var hash = newEntry?.Hash ?? EqualityComparer.Default.GetHashCode(newKey); + var hash = newEntry?.Hash ?? EqualityComparer.Default.GetHashCode(newKey); <# } #> - var index = hash & (buckets.Length - 1); - if (buckets[index] is null) + var index = hash & (buckets.Length - 1); + if (buckets[index] is null) + { + if (newEntry is null) { - if (newEntry is null) - { - resultingValue = value; - buckets[index] = new Entry(newKey, resultingValue, hash); - } - else - { - resultingValue = newEntry.Value; - buckets[index] = newEntry; - } + resultingValue = value; + buckets[index] = new Entry(newKey, resultingValue, hash); } else { - var lastEntry = buckets[index]; - while (true) - { + resultingValue = newEntry.Value; + buckets[index] = newEntry; + } + } + else + { + var lastEntry = buckets[index]; + while (true) + { <# if (x.IsSpecialized) { #> - if (lastEntry.Key == newKey) + if (lastEntry.Key == newKey) <# } else { #> - if (EqualityComparer.Default.Equals(lastEntry.Key, newKey)) + if (EqualityComparer.Default.Equals(lastEntry.Key, newKey)) <# } #> + { + resultingValue = lastEntry.Value; + return false; + } + + if (lastEntry.Next is null) + { + if (newEntry is null) { - resultingValue = lastEntry.Value; - return false; + resultingValue = value; + lastEntry.Next = new Entry(newKey, resultingValue, hash); } - - if (lastEntry.Next is null) + else { - if (newEntry is null) - { - resultingValue = value; - lastEntry.Next = new Entry(newKey, resultingValue, hash); - } - else - { - resultingValue = newEntry.Value; - lastEntry.Next = newEntry; - } - break; + resultingValue = newEntry.Value; + lastEntry.Next = newEntry; } - - lastEntry = lastEntry.Next; + break; } + + lastEntry = lastEntry.Next; } - return true; } - #endregion + return true; } + #endregion + } - /// - /// Calculates bucket capacity. - /// - /// - /// - /// - private static int CalculateCapacity(int collectionSize, float loadFactor) - { - var initialCapacity = (int)(collectionSize / loadFactor); - var capacity = 1; - while (capacity < initialCapacity) - capacity <<= 1; + /// + /// Calculates bucket capacity. + /// + /// + /// + /// + private static int CalculateCapacity(int collectionSize, float loadFactor) + { + var initialCapacity = (int)(collectionSize / loadFactor); + var capacity = 1; + while (capacity < initialCapacity) + capacity <<= 1; - if (capacity < 8) - return 8; + if (capacity < 8) + return 8; - return capacity; - } - #endregion + return capacity; + } + #endregion - #region Get - /// - /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. - /// - /// - /// - /// - public TValue GetValueOrDefault(<#= x.CompatibleName #> key, TValue defaultValue = default) - => this.TryGetValue(key, out var value) - ? value - : defaultValue; - #endregion + #region Get + /// + /// Gets the element that has the specified key in the read-only dictionary or the default value of the element type. + /// + /// + /// + /// + public TValue GetValueOrDefault(<#= x.CompatibleName #> key, TValue defaultValue = default) + => this.TryGetValue(key, out var value) + ? value + : defaultValue; + #endregion - #region IReadOnlyDictionary implementations - /// - /// Gets the element that has the specified key in the read-only dictionary. - /// - /// The key to locate. - /// The element that has the specified key in the read-only dictionary. - public TValue this[<#= x.CompatibleName #> key] - => this.TryGetValue(key, out var value) - ? value - : throw new KeyNotFoundException(); - - - /// - /// Gets an enumerable collection that contains the keys in the read-only dictionary. - /// - public IEnumerable<<#= x.CompatibleName #>> Keys - => throw new NotImplementedException(); - - - /// - /// Gets an enumerable collection that contains the values in the read-only dictionary. - /// - public IEnumerable Values - => throw new NotImplementedException(); - - - /// - /// Gets the number of elements in the collection. - /// - public int Count - => this.size; - - - /// - /// Determines whether the read-only dictionary contains an element that has the specified key. - /// - /// The key to locate. - /// - /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. - /// - public bool ContainsKey(<#= x.CompatibleName #> key) - => this.TryGetValue(key, out _); - - - /// - /// Gets the value that is associated with the specified key. - /// - /// The key to locate. - /// - /// When this method returns, the value associated with the specified key, if the key is found; - /// otherwise, the default value for the type of the value parameter. - /// This parameter is passed uninitialized. - /// - /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetValue(<#= x.CompatibleName #> key, out TValue value) - { + #region IReadOnlyDictionary implementations + /// + /// Gets the element that has the specified key in the read-only dictionary. + /// + /// The key to locate. + /// The element that has the specified key in the read-only dictionary. + public TValue this[<#= x.CompatibleName #> key] + => this.TryGetValue(key, out var value) + ? value + : throw new KeyNotFoundException(); + + + /// + /// Gets an enumerable collection that contains the keys in the read-only dictionary. + /// + public IEnumerable<<#= x.CompatibleName #>> Keys + => throw new NotImplementedException(); + + + /// + /// Gets an enumerable collection that contains the values in the read-only dictionary. + /// + public IEnumerable Values + => throw new NotImplementedException(); + + + /// + /// Gets the number of elements in the collection. + /// + public int Count + => this.size; + + + /// + /// Determines whether the read-only dictionary contains an element that has the specified key. + /// + /// The key to locate. + /// + /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. + /// + public bool ContainsKey(<#= x.CompatibleName #> key) + => this.TryGetValue(key, out _); + + + /// + /// Gets the value that is associated with the specified key. + /// + /// The key to locate. + /// + /// When this method returns, the value associated with the specified key, if the key is found; + /// otherwise, the default value for the type of the value parameter. + /// This parameter is passed uninitialized. + /// + /// true if the object that implements the interface contains an element that has the specified key; otherwise, false. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(<#= x.CompatibleName #> key, out TValue value) + { <# if (x.IsSpecialized) { #> - var hash = key.GetHashCode(); + var hash = key.GetHashCode(); <# } else { #> - var hash = EqualityComparer.Default.GetHashCode(key); + var hash = EqualityComparer.Default.GetHashCode(key); <# } #> - var index = hash & (this.buckets.Length - 1); - var next = this.buckets[index]; - while (next is not null) - { + var index = hash & (this.buckets.Length - 1); + var next = this.buckets[index]; + while (next is not null) + { <# if (x.IsSpecialized) { #> - if (next.Key == key) + if (next.Key == key) <# } else { #> - if (EqualityComparer.Default.Equals(next.Key, key)) + if (EqualityComparer.Default.Equals(next.Key, key)) <# } #> - { - value = next.Value; - return true; - } - next = next.Next; + { + value = next.Value; + return true; } - value = default; - return false; + next = next.Next; } + value = default; + return false; + } - /// - /// Returns an enumerator that iterates through the collection. - /// - /// An enumerator that can be used to iterate through the collection. - public IEnumerator, TValue>> GetEnumerator() - => throw new NotImplementedException(); + /// + /// Returns an enumerator that iterates through the collection. + /// + /// An enumerator that can be used to iterate through the collection. + public IEnumerator, TValue>> GetEnumerator() + => throw new NotImplementedException(); - /// - /// Returns an enumerator that iterates through a collection. - /// - /// An object that can be used to iterate through the collection. - IEnumerator IEnumerable.GetEnumerator() - => throw new NotImplementedException(); - #endregion + /// + /// Returns an enumerator that iterates through a collection. + /// + /// An object that can be used to iterate through the collection. + IEnumerator IEnumerable.GetEnumerator() + => throw new NotImplementedException(); + #endregion - #region Inner Classes - /// - /// Represents entry. - /// - private class Entry - { - public readonly <#= x.CompatibleName #> Key; - public readonly TValue Value; - public readonly int Hash; - public Entry Next; + #region Inner Classes + /// + /// Represents entry. + /// + private class Entry + { + public readonly <#= x.CompatibleName #> Key; + public readonly TValue Value; + public readonly int Hash; + public Entry Next; - public Entry(<#= x.CompatibleName #> key, TValue value, int hash) - { - this.Key = key; - this.Value = value; - this.Hash = hash; - } + public Entry(<#= x.CompatibleName #> key, TValue value, int hash) + { + this.Key = key; + this.Value = value; + this.Hash = hash; } - #endregion } + #endregion +} <# } #> -} diff --git a/src/DeclarativeSql/Internals/IsExternalInit.cs b/src/DeclarativeSql/Internals/IsExternalInit.cs index e35881c..7b4a6f2 100644 --- a/src/DeclarativeSql/Internals/IsExternalInit.cs +++ b/src/DeclarativeSql/Internals/IsExternalInit.cs @@ -2,9 +2,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace System.Runtime.CompilerServices -{ - internal sealed class IsExternalInit - { } -} +namespace System.Runtime.CompilerServices; + +internal sealed class IsExternalInit +{ } #endif diff --git a/src/DeclarativeSql/Internals/NumericHelper.cs b/src/DeclarativeSql/Internals/NumericHelper.cs index d3fccaa..386da25 100644 --- a/src/DeclarativeSql/Internals/NumericHelper.cs +++ b/src/DeclarativeSql/Internals/NumericHelper.cs @@ -1,40 +1,39 @@ using System; +namespace DeclarativeSql.Internals; -namespace DeclarativeSql.Internals + +/// +/// Provides helper methods for numeric. +/// +internal static class NumericHelper { /// - /// Provides helper methods for numeric. + /// Gets the number of digits of the specified value. /// - internal static class NumericHelper + /// + /// + /// http://smdn.jp/programming/netfx/tips/get_number_of_digits/ + public static byte GetDigit(int value) { - /// - /// Gets the number of digits of the specified value. - /// - /// - /// - /// http://smdn.jp/programming/netfx/tips/get_number_of_digits/ - public static byte GetDigit(int value) - { - //--- 0 is special - if (value == 0) - return 1; + //--- 0 is special + if (value == 0) + return 1; - //--- If smaller value, dividing by 10 is faster - if (value <= 10000) + //--- If smaller value, dividing by 10 is faster + if (value <= 10000) + { + byte digit = 1; + while (value >= 10) { - byte digit = 1; - while (value >= 10) - { - value /= 10; - digit++; - } - return digit; + value /= 10; + digit++; } - - //--- When the number is large, calculates from the logarithm - return (byte)(unchecked((byte)Math.Log10(value)) + 1); + return digit; } + + //--- When the number is large, calculates from the logarithm + return (byte)(unchecked((byte)Math.Log10(value)) + 1); } } diff --git a/src/DeclarativeSql/Internals/ReadOnlyArray.cs b/src/DeclarativeSql/Internals/ReadOnlyArray.cs index ff79e40..e6b348e 100644 --- a/src/DeclarativeSql/Internals/ReadOnlyArray.cs +++ b/src/DeclarativeSql/Internals/ReadOnlyArray.cs @@ -3,195 +3,194 @@ using System.Collections.Generic; using System.Linq; +namespace DeclarativeSql.Internals; -namespace DeclarativeSql.Internals + +/// +/// Provides the readonly array. +/// +/// +internal sealed class ReadOnlyArray : IReadOnlyList { + #region Fields + private readonly T[] source; + #endregion + + + #region Constructors /// - /// Provides the readonly array. + /// Creates instance. /// - /// - internal sealed class ReadOnlyArray : IReadOnlyList - { - #region Fields - private readonly T[] source; - #endregion + /// + public ReadOnlyArray(T[] source) + => this.source = source; + #endregion - #region Constructors - /// - /// Creates instance. - /// - /// - public ReadOnlyArray(T[] source) - => this.source = source; - #endregion + #region Custom enumerator + /// + /// Returns an enumerator that iterates through the collection. + /// + /// An enumerator that can be used to iterate through the collection. + public Enumerator GetEnumerator() + => new(this.source); + #endregion - #region Custom enumerator - /// - /// Returns an enumerator that iterates through the collection. - /// - /// An enumerator that can be used to iterate through the collection. - public Enumerator GetEnumerator() - => new(this.source); - #endregion + #region IReadOnlyList implementations + /// + /// Gets the element at the specified index in the read-only list. + /// + /// The zero-based index of the element to get. + /// The element at the specified index in the read-only list. + public T this[int index] + => this.source[index]; - #region IReadOnlyList implementations - /// - /// Gets the element at the specified index in the read-only list. - /// - /// The zero-based index of the element to get. - /// The element at the specified index in the read-only list. - public T this[int index] - => this.source[index]; + /// + /// Gets the number of elements in the collection. + /// + public int Count + => this.source.Length; - /// - /// Gets the number of elements in the collection. - /// - public int Count - => this.source.Length; + /// + /// Returns an enumerator that iterates through the collection. + /// + /// An enumerator that can be used to iterate through the collection. + IEnumerator IEnumerable.GetEnumerator() + => new RefEnumerator(this.source); - /// - /// Returns an enumerator that iterates through the collection. - /// - /// An enumerator that can be used to iterate through the collection. - IEnumerator IEnumerable.GetEnumerator() - => new RefEnumerator(this.source); + /// + /// Returns an enumerator that iterates through a collection. + /// + /// An object that can be used to iterate through the collection. + IEnumerator IEnumerable.GetEnumerator() + => this.source.GetEnumerator(); + #endregion - /// - /// Returns an enumerator that iterates through a collection. - /// - /// An object that can be used to iterate through the collection. - IEnumerator IEnumerable.GetEnumerator() - => this.source.GetEnumerator(); + #region Enumerator + /// + /// Provides an enumerator as value type that iterates through the collection. + /// + public struct Enumerator : IEnumerator + { + #region Fields + private readonly T[] source; + private int index; #endregion - #region Enumerator - /// - /// Provides an enumerator as value type that iterates through the collection. - /// - public struct Enumerator : IEnumerator + #region Constructors + internal Enumerator(T[] source) { - #region Fields - private readonly T[] source; - private int index; - #endregion + this.source = source; + this.index = -1; + } + #endregion - #region Constructors - internal Enumerator(T[] source) - { - this.source = source; - this.index = -1; - } - #endregion + #region IEnumerator implementations + public T Current + => this.source[this.index]; - #region IEnumerator implementations - public T Current - => this.source[this.index]; + object? IEnumerator.Current + => this.Current; - object? IEnumerator.Current - => this.Current; + public void Dispose() + { } - public void Dispose() - { } + public bool MoveNext() + { + this.index++; + return (uint)this.index < (uint)this.source.Length; + } - public bool MoveNext() - { - this.index++; - return (uint)this.index < (uint)this.source.Length; - } + public void Reset() + => this.index = -1; + #endregion + } - public void Reset() - => this.index = -1; - #endregion - } + /// + /// Provides an enumerator as reference type that iterates through the collection. + /// + internal class RefEnumerator : IEnumerator + { + #region Fields + private readonly T[] source; + private int index; + #endregion - /// - /// Provides an enumerator as reference type that iterates through the collection. - /// - internal class RefEnumerator : IEnumerator + #region Constructors + internal RefEnumerator(T[] source) { - #region Fields - private readonly T[] source; - private int index; - #endregion - - - #region Constructors - internal RefEnumerator(T[] source) - { - this.source = source; - this.index = -1; - } - #endregion + this.source = source; + this.index = -1; + } + #endregion - #region IEnumerator implementations - public T Current - => this.source[this.index]; + #region IEnumerator implementations + public T Current + => this.source[this.index]; - object? IEnumerator.Current - => this.Current; + object? IEnumerator.Current + => this.Current; - public void Dispose() - { } + public void Dispose() + { } - public bool MoveNext() - { - this.index++; - return (uint)this.index < (uint)this.source.Length; - } + public bool MoveNext() + { + this.index++; + return (uint)this.index < (uint)this.source.Length; + } - public void Reset() - => this.index = -1; - #endregion - } + public void Reset() + => this.index = -1; #endregion } + #endregion +} +/// +/// Provides extension methods. +/// +internal static class ReadOnlyArrayExtensions +{ /// - /// Provides extension methods. + /// Converts to . /// - internal static class ReadOnlyArrayExtensions - { - /// - /// Converts to . - /// - /// - /// - /// - public static ReadOnlyArray ToReadOnlyArray(this IEnumerable source) - => source is T[] array - ? new(array) - : new(source.ToArray()); - - - /// - /// Converts to . - /// - /// - /// - /// - public static ReadOnlyArray AsReadOnly(this T[] source) - => new(source); - } + /// + /// + /// + public static ReadOnlyArray ToReadOnlyArray(this IEnumerable source) + => source is T[] array + ? new(array) + : new(source.ToArray()); + + + /// + /// Converts to . + /// + /// + /// + /// + public static ReadOnlyArray AsReadOnly(this T[] source) + => new(source); } diff --git a/src/DeclarativeSql/Internals/TypeExtensions.cs b/src/DeclarativeSql/Internals/TypeExtensions.cs index 6e3cb1d..b327ada 100644 --- a/src/DeclarativeSql/Internals/TypeExtensions.cs +++ b/src/DeclarativeSql/Internals/TypeExtensions.cs @@ -1,21 +1,20 @@ using System; +namespace DeclarativeSql.Internals; -namespace DeclarativeSql.Internals + +/// +/// Provides extension methods. +/// +internal static class TypeExtensions { /// - /// Provides extension methods. + /// Gets whether specified type is . /// - internal static class TypeExtensions - { - /// - /// Gets whether specified type is . - /// - /// - /// - public static bool IsNullable(this Type type) - => type.IsGenericType - && type.GetGenericTypeDefinition() == typeof(Nullable<>); - } + /// + /// + public static bool IsNullable(this Type type) + => type.IsGenericType + && type.GetGenericTypeDefinition() == typeof(Nullable<>); } diff --git a/src/DeclarativeSql/Mapping/ColumnInfo.cs b/src/DeclarativeSql/Mapping/ColumnInfo.cs index 71dc283..a177542 100644 --- a/src/DeclarativeSql/Mapping/ColumnInfo.cs +++ b/src/DeclarativeSql/Mapping/ColumnInfo.cs @@ -4,135 +4,134 @@ using System.Reflection; using DeclarativeSql.Annotations; +namespace DeclarativeSql.Mapping; -namespace DeclarativeSql.Mapping + +/// +/// Provides column mapping information. +/// +internal sealed class ColumnInfo { + #region Properties /// - /// Provides column mapping information. + /// Gets the name of member. /// - internal sealed class ColumnInfo - { - #region Properties - /// - /// Gets the name of member. - /// - public string MemberName { get; } + public string MemberName { get; } + + + /// + /// Gets the type of member. + /// + public Type MemberType { get; } + + /// + /// Gets the name of column. + /// + public string ColumnName { get; } - /// - /// Gets the type of member. - /// - public Type MemberType { get; } + /// + /// Gets the type of column. + /// + public DbType? ColumnType { get; } - /// - /// Gets the name of column. - /// - public string ColumnName { get; } + + /// + /// Gets the default value. + /// + public object? DefaultValue { get; } - /// - /// Gets the type of column. - /// - public DbType? ColumnType { get; } - - - /// - /// Gets the default value. - /// - public object? DefaultValue { get; } - - - /// - /// Gets whether primary key. - /// - public bool IsPrimaryKey { get; } - - - /// - /// Gets whether auto increment numbering. - /// - public bool IsAutoIncrement { get; } - - - /// - /// Gets whether allowing null. - /// - public bool AllowNull { get; } - - - /// - /// Gets whether unique constraint. - /// - public bool IsUnique - => this.UniqueIndex.HasValue; - - - /// - /// Gets the index of unique constraint. - /// - public int? UniqueIndex { get; } - - - /// - /// Gets whether CreatedAt column. - /// - public bool IsCreatedAt { get; } - - - /// - /// Gets whether ModifiedAt column. - /// - public bool IsModifiedAt { get; } - #endregion - - - #region Constructors - /// - /// Creates instance. - /// - /// - /// - internal ColumnInfo(DbKind database, PropertyInfo property) - : this(database, property, property.PropertyType) - {} - - - /// - /// Creates instance. - /// - /// - /// - internal ColumnInfo(DbKind database, FieldInfo field) - : this(database, field, field.FieldType) - {} - - - /// - /// Creates instance. - /// - /// - /// - /// - private ColumnInfo(DbKind database, MemberInfo member, Type memberType) - { - var column = member.GetCustomAttributes(true).FirstOrDefault(x => x.Database == database); - var @default = member.GetCustomAttributes(true).FirstOrDefault(x => x.Database == database); - var unique = member.GetCustomAttribute(true); - - this.MemberName = member.Name; - this.MemberType = memberType; - this.ColumnName = column?.Name ?? member.Name; - this.ColumnType = column?.Type; - this.DefaultValue = @default?.Value; - this.IsPrimaryKey = Attribute.IsDefined(member, typeof(PrimaryKeyAttribute)); - this.IsAutoIncrement = Attribute.IsDefined(member, typeof(AutoIncrementAttribute)); - this.AllowNull = Attribute.IsDefined(member, typeof(AllowNullAttribute)); - this.UniqueIndex = this.IsPrimaryKey ? -1 : (int?)unique?.Index; - this.IsCreatedAt = Attribute.IsDefined(member, typeof(CreatedAtAttribute)); - this.IsModifiedAt = Attribute.IsDefined(member, typeof(ModifiedAtAttribute)); - } - #endregion + /// + /// Gets whether primary key. + /// + public bool IsPrimaryKey { get; } + + + /// + /// Gets whether auto increment numbering. + /// + public bool IsAutoIncrement { get; } + + + /// + /// Gets whether allowing null. + /// + public bool AllowNull { get; } + + + /// + /// Gets whether unique constraint. + /// + public bool IsUnique + => this.UniqueIndex.HasValue; + + + /// + /// Gets the index of unique constraint. + /// + public int? UniqueIndex { get; } + + + /// + /// Gets whether CreatedAt column. + /// + public bool IsCreatedAt { get; } + + + /// + /// Gets whether ModifiedAt column. + /// + public bool IsModifiedAt { get; } + #endregion + + + #region Constructors + /// + /// Creates instance. + /// + /// + /// + internal ColumnInfo(DbKind database, PropertyInfo property) + : this(database, property, property.PropertyType) + { } + + + /// + /// Creates instance. + /// + /// + /// + internal ColumnInfo(DbKind database, FieldInfo field) + : this(database, field, field.FieldType) + { } + + + /// + /// Creates instance. + /// + /// + /// + /// + private ColumnInfo(DbKind database, MemberInfo member, Type memberType) + { + var column = member.GetCustomAttributes(true).FirstOrDefault(x => x.Database == database); + var @default = member.GetCustomAttributes(true).FirstOrDefault(x => x.Database == database); + var unique = member.GetCustomAttribute(true); + + this.MemberName = member.Name; + this.MemberType = memberType; + this.ColumnName = column?.Name ?? member.Name; + this.ColumnType = column?.Type; + this.DefaultValue = @default?.Value; + this.IsPrimaryKey = Attribute.IsDefined(member, typeof(PrimaryKeyAttribute)); + this.IsAutoIncrement = Attribute.IsDefined(member, typeof(AutoIncrementAttribute)); + this.AllowNull = Attribute.IsDefined(member, typeof(AllowNullAttribute)); + this.UniqueIndex = this.IsPrimaryKey ? -1 : (int?)unique?.Index; + this.IsCreatedAt = Attribute.IsDefined(member, typeof(CreatedAtAttribute)); + this.IsModifiedAt = Attribute.IsDefined(member, typeof(ModifiedAtAttribute)); } + #endregion } diff --git a/src/DeclarativeSql/Mapping/TableInfo.cs b/src/DeclarativeSql/Mapping/TableInfo.cs index 2290831..06f62c5 100644 --- a/src/DeclarativeSql/Mapping/TableInfo.cs +++ b/src/DeclarativeSql/Mapping/TableInfo.cs @@ -6,140 +6,139 @@ using DeclarativeSql.Annotations; using DeclarativeSql.Internals; +namespace DeclarativeSql.Mapping; -namespace DeclarativeSql.Mapping + +/// +/// Provides table mapping information. +/// +internal sealed class TableInfo { + #region Properties /// - /// Provides table mapping information. + /// Gets the kind of database. /// - internal sealed class TableInfo - { - #region Properties - /// - /// Gets the kind of database. - /// - public DbKind Database { get; private init; } + public DbKind Database { get; private init; } - /// - /// Gets the type that is mapped to the table. - /// - public Type Type { get; private init; } + /// + /// Gets the type that is mapped to the table. + /// + public Type Type { get; private init; } - /// - /// Gets the schema name. - /// - public string? Schema { get; private init; } + /// + /// Gets the schema name. + /// + public string? Schema { get; private init; } - /// - /// Gets the table name. - /// - public string Name { get; private init; } + /// + /// Gets the table name. + /// + public string Name { get; private init; } - /// - /// Gets the full table name. - /// - public string FullName { get; private init; } + /// + /// Gets the full table name. + /// + public string FullName { get; private init; } - /// - /// Gets the column mapping information. - /// - public ReadOnlyArray Columns { get; private init; } + /// + /// Gets the column mapping information. + /// + public ReadOnlyArray Columns { get; private init; } - /// - /// Gets the column mapping information by member name. - /// - public FrozenStringKeyDictionary ColumnsByMemberName { get; private init; } - #endregion + /// + /// Gets the column mapping information by member name. + /// + public FrozenStringKeyDictionary ColumnsByMemberName { get; private init; } + #endregion - #region Constructors + #region Constructors #pragma warning disable CS8618 - /// - /// Creates instance. - /// - private TableInfo() - {} + /// + /// Creates instance. + /// + private TableInfo() + { } #pragma warning restore CS8618 - #endregion + #endregion - #region Get + #region Get + /// + /// Gets the table mapping information corresponding to the specified type. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TableInfo Get(DbKind database) + => Cache.Instances.TryGetValue(database, out var value) + ? value + : throw new NotSupportedException(); + #endregion + + + #region Internal Cache + /// + /// Provides cache. + /// + /// + private static class Cache + { /// - /// Gets the table mapping information corresponding to the specified type. + /// Gets the instances by . /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TableInfo Get(DbKind database) - => Cache.Instances.TryGetValue(database, out var value) - ? value - : throw new NotSupportedException(); - #endregion - - - #region Internal Cache + public static FrozenDictionary Instances { get; } + + /// - /// Provides cache. + /// Static constructors /// - /// - private static class Cache + static Cache() { - /// - /// Gets the instances by . - /// - public static FrozenDictionary Instances { get; } - - - /// - /// Static constructors - /// - static Cache() - { - var type = typeof(T); - var flags = BindingFlags.Instance | BindingFlags.Public; - var attributes = type.GetCustomAttributes(true).ToDictionary(x => x.Database); - var properties = type.GetProperties(flags); - var fields = type.GetFields(flags); - Instances - = Enum.GetValues(typeof(DbKind)) - .Cast() - .Select(db => + var type = typeof(T); + var flags = BindingFlags.Instance | BindingFlags.Public; + var attributes = type.GetCustomAttributes(true).ToDictionary(x => x.Database); + var properties = type.GetProperties(flags); + var fields = type.GetFields(flags); + Instances + = Enum.GetValues(typeof(DbKind)) + .Cast() + .Select(db => + { + attributes.TryGetValue(db, out var tableAttr); + var provider = DbProvider.ByDatabase[db]; + var b = provider.KeywordBracket; + var schema = tableAttr?.Schema ?? provider.DefaultSchema; + var name = tableAttr?.Name ?? type.Name; + var columns + = properties.Select(x => new ColumnInfo(db, x)) + .Concat(fields.Select(x => new ColumnInfo(db, x))) + .ToReadOnlyArray(); + var table = new TableInfo { - attributes.TryGetValue(db, out var tableAttr); - var provider = DbProvider.ByDatabase[db]; - var b = provider.KeywordBracket; - var schema = tableAttr?.Schema ?? provider.DefaultSchema; - var name = tableAttr?.Name ?? type.Name; - var columns - = properties.Select(x => new ColumnInfo(db, x)) - .Concat(fields.Select(x => new ColumnInfo(db, x))) - .ToReadOnlyArray(); - var table = new TableInfo - { - Database = db, - Type = type, - Schema = schema, - Name = name, - FullName - = string.IsNullOrEmpty(schema) - ? ZString.Concat(b.Begin, name, b.End) - : ZString.Concat(b.Begin, schema, b.End, '.', b.Begin, name, b.End), - Columns = columns, - ColumnsByMemberName = columns.ToFrozenStringKeyDictionary(x => x.MemberName), - }; - return (db, table); - }) - .ToFrozenDictionary(x => x.db, x => x.table); - } + Database = db, + Type = type, + Schema = schema, + Name = name, + FullName + = string.IsNullOrEmpty(schema) + ? ZString.Concat(b.Begin, name, b.End) + : ZString.Concat(b.Begin, schema, b.End, '.', b.Begin, name, b.End), + Columns = columns, + ColumnsByMemberName = columns.ToFrozenStringKeyDictionary(x => x.MemberName), + }; + return (db, table); + }) + .ToFrozenDictionary(x => x.db, x => x.table); } - #endregion } + #endregion } diff --git a/src/DeclarativeSql/Sql/BindParameter.cs b/src/DeclarativeSql/Sql/BindParameter.cs index bb1aca7..f546004 100644 --- a/src/DeclarativeSql/Sql/BindParameter.cs +++ b/src/DeclarativeSql/Sql/BindParameter.cs @@ -7,320 +7,319 @@ -namespace DeclarativeSql.Sql +namespace DeclarativeSql.Sql; + +/// +/// Represents bind parameters. +/// +public sealed class BindParameter : IDictionary, IReadOnlyDictionary { + #region Properties + /// + /// Gets the key/value store that held inside. + /// + private IDictionary Inner { get; } + #endregion + + + #region Constructors + /// + /// Creates instance. + /// + public BindParameter() + : this(new Dictionary()) + { } + + /// - /// Represents bind parameters. + /// Creates instance. /// - public sealed class BindParameter : IDictionary, IReadOnlyDictionary + /// + public BindParameter(IDictionary source) + => this.Inner = source; + #endregion + + + #region IDictionary implementations + /// + /// Gets or sets the element with the specified key. + /// + /// + /// + public object? this[string key] { - #region Properties - /// - /// Gets the key/value store that held inside. - /// - private IDictionary Inner { get; } - #endregion - - - #region Constructors - /// - /// Creates instance. - /// - public BindParameter() - : this(new Dictionary()) - {} - - - /// - /// Creates instance. - /// - /// - public BindParameter(IDictionary source) - => this.Inner = source; - #endregion - - - #region IDictionary implementations - /// - /// Gets or sets the element with the specified key. - /// - /// - /// - public object? this[string key] - { - get => this.Inner[key]; - set => this.Inner[key] = value; - } + get => this.Inner[key]; + set => this.Inner[key] = value; + } + + + /// + /// Gets an containing the keys of the . + /// + ICollection IDictionary.Keys + => this.Inner.Keys; + + + /// + /// Gets an containing the values of the . + /// + ICollection IDictionary.Values + => this.Inner.Values; + + + /// + /// Gets the number of elements contained in the . + /// + public int Count + => this.Inner.Count; - /// - /// Gets an containing the keys of the . - /// - ICollection IDictionary.Keys - => this.Inner.Keys; + /// + /// Gets a value indicating whether the is read-only. + /// + bool ICollection>.IsReadOnly + => this.Inner.IsReadOnly; - /// - /// Gets an containing the values of the . - /// - ICollection IDictionary.Values - => this.Inner.Values; + /// + /// Adds an item to the . + /// + /// + /// + public void Add(string key, object? value) + => this.Inner.Add(key, value); - /// - /// Gets the number of elements contained in the . - /// - public int Count - => this.Inner.Count; + /// + /// Adds an item to the . + /// + /// + void ICollection>.Add(KeyValuePair item) + => this.Inner.Add(item); - /// - /// Gets a value indicating whether the is read-only. - /// - bool ICollection>.IsReadOnly - => this.Inner.IsReadOnly; + /// + /// Removes all items from the . + /// + public void Clear() + => this.Inner.Clear(); - /// - /// Adds an item to the . - /// - /// - /// - public void Add(string key, object? value) - => this.Inner.Add(key, value); + /// + /// Determines whether the contains a specific value. + /// + /// + /// + bool ICollection>.Contains(KeyValuePair item) + => this.Inner.Contains(item); - /// - /// Adds an item to the . - /// - /// - void ICollection>.Add(KeyValuePair item) - => this.Inner.Add(item); + /// + /// Determines whether the contains an element with the specified key. + /// + /// + /// + public bool ContainsKey(string key) + => this.Inner.ContainsKey(key); - /// - /// Removes all items from the . - /// - public void Clear() - => this.Inner.Clear(); - - - /// - /// Determines whether the contains a specific value. - /// - /// - /// - bool ICollection>.Contains(KeyValuePair item) - => this.Inner.Contains(item); - - - /// - /// Determines whether the contains an element with the specified key. - /// - /// - /// - public bool ContainsKey(string key) - => this.Inner.ContainsKey(key); - - - /// - /// Copies the elements of the to an , starting at a particular index. - /// - /// - /// - void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) - => this.Inner.CopyTo(array, arrayIndex); - - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - public IEnumerator> GetEnumerator() - => this.Inner.GetEnumerator(); - - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - IEnumerator IEnumerable.GetEnumerator() - => this.Inner.GetEnumerator(); - - - /// - /// Removes the first occurrence of a specific object from the . - /// - /// - /// - public bool Remove(string key) - => this.Inner.Remove(key); - - - /// - /// Removes the first occurrence of a specific object from the . - /// - /// - /// - bool ICollection>.Remove(KeyValuePair item) - => this.Inner.Remove(item); - - - /// - /// Gets the value associated with the specified key. - /// - /// - /// - /// - public bool TryGetValue(string key, out object? value) - => this.Inner.TryGetValue(key, out value); - #endregion - - - #region IReadOnlyDictionary implementations - /// - /// Gets an enumerable collection that contains the keys in the read-only dictionary. - /// - public IEnumerable Keys - => this.Inner.Keys; - - - /// - /// Gets an enumerable collection that contains the values in the read-only dictionary. - /// - public IEnumerable Values - => this.Inner.Values; - #endregion - - - #region Create - /// - /// Creates an instance from the specified object. - /// - /// - /// - /// - public static BindParameter From(T obj) - { - var result = new BindParameter(); - var members = TypeAccessor.Create(typeof(T)).GetMembers(); - var accessor = ObjectAccessor.Create(obj); - for (var i = 0; i < members.Count; i++) - { - var member = members[i]; - if (member.CanRead) - result.Add(member.Name, accessor[member.Name]); - } - return result; - } + /// + /// Copies the elements of the to an , starting at a particular index. + /// + /// + /// + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + => this.Inner.CopyTo(array, arrayIndex); - /// - /// Clones the instance. - /// - /// - public BindParameter Clone() - { - IDictionary result = new BindParameter(); - foreach (var x in this) - result.Add(x); - return (BindParameter)result; - } - #endregion + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + public IEnumerator> GetEnumerator() + => this.Inner.GetEnumerator(); - #region Update - /// - /// Updates the value of the source property with the matching key name. - /// - /// - /// - public void Update(T source) + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + IEnumerator IEnumerable.GetEnumerator() + => this.Inner.GetEnumerator(); + + + /// + /// Removes the first occurrence of a specific object from the . + /// + /// + /// + public bool Remove(string key) + => this.Inner.Remove(key); + + + /// + /// Removes the first occurrence of a specific object from the . + /// + /// + /// + bool ICollection>.Remove(KeyValuePair item) + => this.Inner.Remove(item); + + + /// + /// Gets the value associated with the specified key. + /// + /// + /// + /// + public bool TryGetValue(string key, out object? value) + => this.Inner.TryGetValue(key, out value); + #endregion + + + #region IReadOnlyDictionary implementations + /// + /// Gets an enumerable collection that contains the keys in the read-only dictionary. + /// + public IEnumerable Keys + => this.Inner.Keys; + + + /// + /// Gets an enumerable collection that contains the values in the read-only dictionary. + /// + public IEnumerable Values + => this.Inner.Values; + #endregion + + + #region Create + /// + /// Creates an instance from the specified object. + /// + /// + /// + /// + public static BindParameter From(T obj) + { + var result = new BindParameter(); + var members = TypeAccessor.Create(typeof(T)).GetMembers(); + var accessor = ObjectAccessor.Create(obj); + for (var i = 0; i < members.Count; i++) { - var accessor = ObjectAccessor.Create(source); - var members = TypeAccessor.Create(typeof(T)).GetMembers(); - for (var i = 0; i < members.Count; i++) - { - var member = members[i]; - if (member.CanRead && this.ContainsKey(member.Name)) // if exists same name - this[member.Name] = accessor[member.Name]; - } + var member = members[i]; + if (member.CanRead) + result.Add(member.Name, accessor[member.Name]); } - #endregion + return result; + } + + /// + /// Clones the instance. + /// + /// + public BindParameter Clone() + { + IDictionary result = new BindParameter(); + foreach (var x in this) + result.Add(x); + return (BindParameter)result; + } + #endregion - #region Append - /// - /// Appends the specified values. - /// - /// - public void Append(IEnumerable> kvs) + + #region Update + /// + /// Updates the value of the source property with the matching key name. + /// + /// + /// + public void Update(T source) + { + var accessor = ObjectAccessor.Create(source); + var members = TypeAccessor.Create(typeof(T)).GetMembers(); + for (var i = 0; i < members.Count; i++) { - foreach (var x in kvs) - this.Add(x.Key, x.Value); + var member = members[i]; + if (member.CanRead && this.ContainsKey(member.Name)) // if exists same name + this[member.Name] = accessor[member.Name]; } + } + #endregion - /// - /// Appends the specified values. - /// - /// - public void Append(T obj) + #region Append + /// + /// Appends the specified values. + /// + /// + public void Append(IEnumerable> kvs) + { + foreach (var x in kvs) + this.Add(x.Key, x.Value); + } + + + /// + /// Appends the specified values. + /// + /// + public void Append(T obj) + { + var members = TypeAccessor.Create(typeof(T)).GetMembers(); + var accessor = ObjectAccessor.Create(obj); + for (var i = 0; i < members.Count; i++) { - var members = TypeAccessor.Create(typeof(T)).GetMembers(); - var accessor = ObjectAccessor.Create(obj); - for (var i = 0; i < members.Count; i++) - { - var member = members[i]; - if (member.CanRead) - this.Add(member.Name, accessor[member.Name]); - } + var member = members[i]; + if (member.CanRead) + this.Add(member.Name, accessor[member.Name]); } + } - /// - /// Appends the specified values. - /// - /// - /// - public void Append(T obj, Expression> targetProperties) + /// + /// Appends the specified values. + /// + /// + /// + public void Append(T obj, Expression> targetProperties) + { + var memberNames = ExpressionHelper.GetMemberNames(targetProperties); + var members = TypeAccessor.Create(typeof(T)).GetMembers(); + var accessor = ObjectAccessor.Create(obj); + for (var i = 0; i < members.Count; i++) { - var memberNames = ExpressionHelper.GetMemberNames(targetProperties); - var members = TypeAccessor.Create(typeof(T)).GetMembers(); - var accessor = ObjectAccessor.Create(obj); - for (var i = 0; i < members.Count; i++) - { - var member = members[i]; - if (!member.CanRead) continue; - if (!memberNames.Contains(member.Name)) continue; - this.Add(member.Name, accessor[member.Name]); - } + var member = members[i]; + if (!member.CanRead) continue; + if (!memberNames.Contains(member.Name)) continue; + this.Add(member.Name, accessor[member.Name]); } - #endregion + } + #endregion - #region Overwrite - /// - /// Overwrites by the specified values. - /// - /// - /// - internal void Overwrite(T obj) + #region Overwrite + /// + /// Overwrites by the specified values. + /// + /// + /// + internal void Overwrite(T obj) + { + var members = TypeAccessor.Create(typeof(T)).GetMembers(); + var accessor = ObjectAccessor.Create(obj); + for (var i = 0; i < members.Count; i++) { - var members = TypeAccessor.Create(typeof(T)).GetMembers(); - var accessor = ObjectAccessor.Create(obj); - for (var i = 0; i < members.Count; i++) - { - var member = members[i]; - if (!member.CanRead) - continue; - - if (!this.Inner.ContainsKey(member.Name)) - continue; - - this.Inner[member.Name] = accessor[member.Name]; - } + var member = members[i]; + if (!member.CanRead) + continue; + + if (!this.Inner.ContainsKey(member.Name)) + continue; + + this.Inner[member.Name] = accessor[member.Name]; } - #endregion } + #endregion } diff --git a/src/DeclarativeSql/Sql/BracketPair.cs b/src/DeclarativeSql/Sql/BracketPair.cs index 15e6342..376d8b8 100644 --- a/src/DeclarativeSql/Sql/BracketPair.cs +++ b/src/DeclarativeSql/Sql/BracketPair.cs @@ -1,35 +1,36 @@ -namespace DeclarativeSql.Sql +namespace DeclarativeSql.Sql; + + + +/// +/// Represents a begin/end bracket pair. +/// +public readonly struct BracketPair { + #region Properties /// - /// Represents a begin/end bracket pair. + /// Gets the begin bracket. /// - public readonly struct BracketPair - { - #region Properties - /// - /// Gets the begin bracket. - /// - public char Begin { get; } + public char Begin { get; } - /// - /// Gets the end bracket. - /// - public char End { get; } - #endregion + /// + /// Gets the end bracket. + /// + public char End { get; } + #endregion - #region Constructors - /// - /// Creates instance. - /// - /// - /// - internal BracketPair(char begin, char end) - { - this.Begin = begin; - this.End = end; - } - #endregion + #region Constructors + /// + /// Creates instance. + /// + /// + /// + internal BracketPair(char begin, char end) + { + this.Begin = begin; + this.End = end; } + #endregion } diff --git a/src/DeclarativeSql/Sql/Clauses/OrderBy.cs b/src/DeclarativeSql/Sql/Clauses/OrderBy.cs index 12dad8c..3afce80 100644 --- a/src/DeclarativeSql/Sql/Clauses/OrderBy.cs +++ b/src/DeclarativeSql/Sql/Clauses/OrderBy.cs @@ -4,60 +4,59 @@ using DeclarativeSql.Internals; using DeclarativeSql.Mapping; +namespace DeclarativeSql.Sql.Clauses; -namespace DeclarativeSql.Sql.Clauses + +/// +/// Represents order by clause. +/// +/// +internal readonly struct OrderBy : ISql { + #region Properties /// - /// Represents order by clause. + /// Gets the expression for the property mapped to the column. /// - /// - internal readonly struct OrderBy : ISql + private Expression> Property { get; } + + + /// + /// Gets whether ascending order. + /// + private bool IsAscending { get; } + #endregion + + + #region Constructors + /// + /// Creates instance. + /// + /// + /// + public OrderBy(Expression> property, bool isAscending) + { + this.Property = property; + this.IsAscending = isAscending; + } + #endregion + + + #region ISql implementations + /// + public void Build(DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter) { - #region Properties - /// - /// Gets the expression for the property mapped to the column. - /// - private Expression> Property { get; } - - - /// - /// Gets whether ascending order. - /// - private bool IsAscending { get; } - #endregion - - - #region Constructors - /// - /// Creates instance. - /// - /// - /// - public OrderBy(Expression> property, bool isAscending) - { - this.Property = property; - this.IsAscending = isAscending; - } - #endregion - - - #region ISql implementations - /// - public void Build(DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter) - { - var propertyName = ExpressionHelper.GetMemberName(this.Property); - var columnName = table.ColumnsByMemberName[propertyName].ColumnName; - var bracket = dbProvider.KeywordBracket; - - builder.AppendLine("order by"); - builder.Append(" "); - builder.Append(bracket.Begin); - builder.Append(columnName); - builder.Append(bracket.End); - if (!this.IsAscending) - builder.Append(" desc"); - } - #endregion + var propertyName = ExpressionHelper.GetMemberName(this.Property); + var columnName = table.ColumnsByMemberName[propertyName].ColumnName; + var bracket = dbProvider.KeywordBracket; + + builder.AppendLine("order by"); + builder.Append(" "); + builder.Append(bracket.Begin); + builder.Append(columnName); + builder.Append(bracket.End); + if (!this.IsAscending) + builder.Append(" desc"); } + #endregion } diff --git a/src/DeclarativeSql/Sql/Clauses/ThenBy.cs b/src/DeclarativeSql/Sql/Clauses/ThenBy.cs index 7f8f567..c579a3a 100644 --- a/src/DeclarativeSql/Sql/Clauses/ThenBy.cs +++ b/src/DeclarativeSql/Sql/Clauses/ThenBy.cs @@ -4,59 +4,58 @@ using DeclarativeSql.Internals; using DeclarativeSql.Mapping; +namespace DeclarativeSql.Sql.Clauses; -namespace DeclarativeSql.Sql.Clauses + +/// +/// Represents then by clause. +/// +/// +internal readonly struct ThenBy : ISql { + #region Properties /// - /// Represents then by clause. + /// Gets the expression for the property mapped to the column. /// - /// - internal readonly struct ThenBy : ISql + private Expression> Property { get; } + + + /// + /// Gets whether ascending order. + /// + private bool IsAscending { get; } + #endregion + + + #region Constructors + /// + /// Creates instance. + /// + /// + /// + public ThenBy(Expression> property, bool isAscending) + { + this.Property = property; + this.IsAscending = isAscending; + } + #endregion + + + #region ISql implementations + /// + public void Build(DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter) { - #region Properties - /// - /// Gets the expression for the property mapped to the column. - /// - private Expression> Property { get; } - - - /// - /// Gets whether ascending order. - /// - private bool IsAscending { get; } - #endregion - - - #region Constructors - /// - /// Creates instance. - /// - /// - /// - public ThenBy(Expression> property, bool isAscending) - { - this.Property = property; - this.IsAscending = isAscending; - } - #endregion - - - #region ISql implementations - /// - public void Build(DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter) - { - var propertyName = ExpressionHelper.GetMemberName(this.Property); - var columnName = table.ColumnsByMemberName[propertyName].ColumnName; - var bracket = dbProvider.KeywordBracket; - - builder.Append(" "); - builder.Append(bracket.Begin); - builder.Append(columnName); - builder.Append(bracket.End); - if (!this.IsAscending) - builder.Append(" desc"); - } - #endregion + var propertyName = ExpressionHelper.GetMemberName(this.Property); + var columnName = table.ColumnsByMemberName[propertyName].ColumnName; + var bracket = dbProvider.KeywordBracket; + + builder.Append(" "); + builder.Append(bracket.Begin); + builder.Append(columnName); + builder.Append(bracket.End); + if (!this.IsAscending) + builder.Append(" desc"); } + #endregion } diff --git a/src/DeclarativeSql/Sql/Clauses/Where.cs b/src/DeclarativeSql/Sql/Clauses/Where.cs index ac4f3a0..99c95a9 100644 --- a/src/DeclarativeSql/Sql/Clauses/Where.cs +++ b/src/DeclarativeSql/Sql/Clauses/Where.cs @@ -10,21 +10,60 @@ using DeclarativeSql.Mapping; using FastMember; +namespace DeclarativeSql.Sql.Clauses; -namespace DeclarativeSql.Sql.Clauses + +/// +/// Represents where clause. +/// +/// +internal readonly struct Where : ISql { + #region Properties /// - /// Represents where clause. + /// Gets the expression that represents the filter condition. /// - /// - internal readonly struct Where : ISql + private Expression> Predicate { get; } + #endregion + + + #region Constructors + /// + /// Creates instance. + /// + /// + public Where(Expression> predicate) + => this.Predicate = predicate; + #endregion + + + #region ISql implementations + /// + public void Build(DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter) { - #region Properties - /// - /// Gets the expression that represents the filter condition. - /// - private Expression> Predicate { get; } + builder.AppendLine("where"); + builder.Append(" "); + + var parameter = this.Predicate.Parameters[0]; + var parser = new Parser(parameter, dbProvider, table, ref builder, ref bindParameter); + parser.Visit(this.Predicate); + } + #endregion + + + #region Analyze expression tree (private class / enum only) + /// + /// Provides a conditional expression analysis. + /// + private unsafe sealed class Parser : ExpressionVisitor + { + #region Fields + private readonly ParameterExpression parameter; + private readonly DbProvider dbProvider; + private readonly TableInfo table; + private readonly void* stringBuilderPointer; + private readonly void* bindParameterPointer; #endregion @@ -32,398 +71,359 @@ namespace DeclarativeSql.Sql.Clauses /// /// Creates instance. /// - /// - public Where(Expression> predicate) - => this.Predicate = predicate; - #endregion - - - #region ISql implementations - /// - public void Build(DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter) + /// + /// + /// + /// + /// + public Parser(ParameterExpression parameter, DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter) { - builder.AppendLine("where"); - builder.Append(" "); - - var parameter = this.Predicate.Parameters[0]; - var parser = new Parser(parameter, dbProvider, table, ref builder, ref bindParameter); - parser.Visit(this.Predicate); + this.parameter = parameter; + this.dbProvider = dbProvider; + this.table = table; + this.stringBuilderPointer = Unsafe.AsPointer(ref builder); + this.bindParameterPointer = Unsafe.AsPointer(ref bindParameter); } #endregion - #region Analyze expression tree (private class / enum only) + #region Overrides /// - /// Provides a conditional expression analysis. + /// Scans the children of . /// - private unsafe sealed class Parser : ExpressionVisitor + /// Target expression + /// + protected override Expression VisitBinary(BinaryExpression expression) { - #region Fields - private readonly ParameterExpression parameter; - private readonly DbProvider dbProvider; - private readonly TableInfo table; - private readonly void* stringBuilderPointer; - private readonly void* bindParameterPointer; - #endregion - - - #region Constructors - /// - /// Creates instance. - /// - /// - /// - /// - /// - /// - public Parser(ParameterExpression parameter, DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter) - { - this.parameter = parameter; - this.dbProvider = dbProvider; - this.table = table; - this.stringBuilderPointer = Unsafe.AsPointer(ref builder); - this.bindParameterPointer = Unsafe.AsPointer(ref bindParameter); - } - #endregion - - - #region Overrides - /// - /// Scans the children of . - /// - /// Target expression - /// - protected override Expression VisitBinary(BinaryExpression expression) + switch (expression.NodeType) { - switch (expression.NodeType) - { - //--- AND/OR : Generated an element that holds the left and right - case ExpressionType.AndAlso: - case ExpressionType.OrElse: - { - this.BuildAndOr(expression); - return expression; - } + //--- AND/OR : Generated an element that holds the left and right + case ExpressionType.AndAlso: + case ExpressionType.OrElse: + { + this.BuildAndOr(expression); + return expression; + } - //--- Comparison operator (<, <=, >=, >, ==, !=) : Extract property name of left node and value of right node - case ExpressionType.LessThan: - case ExpressionType.LessThanOrEqual: - case ExpressionType.GreaterThan: - case ExpressionType.GreaterThanOrEqual: - case ExpressionType.Equal: - case ExpressionType.NotEqual: + //--- Comparison operator (<, <=, >=, >, ==, !=) : Extract property name of left node and value of right node + case ExpressionType.LessThan: + case ExpressionType.LessThanOrEqual: + case ExpressionType.GreaterThan: + case ExpressionType.GreaterThanOrEqual: + case ExpressionType.Equal: + case ExpressionType.NotEqual: + { + #region Local Functions + static (Operator @operator, string propertyName, object? value) getParameter(Parser parser, BinaryExpression expression) { - #region Local Functions - static (Operator @operator, string propertyName, object? value) getParameter(Parser parser, BinaryExpression expression) + //--- 'x.Hoge == value' { - //--- 'x.Hoge == value' + var propertyName = parser.ExtractMemberName(expression.Left); + if (propertyName is not null) { - var propertyName = parser.ExtractMemberName(expression.Left); - if (propertyName is not null) - { - var @operator = OperatorExtensions.From(expression.NodeType); - var value = parser.ExtractValue(expression.Right); - return (@operator, propertyName, value); - } + var @operator = OperatorExtensions.From(expression.NodeType); + var value = parser.ExtractValue(expression.Right); + return (@operator, propertyName, value); } - //--- 'value == x.Hoge' + } + //--- 'value == x.Hoge' + { + var propertyName = parser.ExtractMemberName(expression.Right); + if (propertyName is not null) { - var propertyName = parser.ExtractMemberName(expression.Right); - if (propertyName is not null) - { - var @operator = OperatorExtensions.From(expression.NodeType); - @operator = OperatorExtensions.Flip(@operator); - var value = parser.ExtractValue(expression.Left); - return (@operator, propertyName, value); - } + var @operator = OperatorExtensions.From(expression.NodeType); + @operator = OperatorExtensions.Flip(@operator); + var value = parser.ExtractValue(expression.Left); + return (@operator, propertyName, value); } - //--- Error - throw new InvalidOperationException(); } - #endregion - - var p = getParameter(this, expression); - this.BuildBinary(p.@operator, p.propertyName, p.value); - return expression; + //--- Error + throw new InvalidOperationException(); } - } - return base.VisitBinary(expression); - } - + #endregion - /// - /// Scans the children of . - /// - /// Target expression - /// - protected override Expression VisitMethodCall(MethodCallExpression expression) - { - //--- bool Contains(T value) - if (expression.Method.Name == nameof(Enumerable.Contains)) - { - var t = expression.Method.DeclaringType; - if (t == typeof(Enumerable)) - { - this.BuildInClause(expression, true); - } - else if (t?.Namespace?.StartsWith("System.Collections") ?? false) - { - this.BuildInClause(expression, false); + var p = getParameter(this, expression); + this.BuildBinary(p.@operator, p.propertyName, p.value); + return expression; } - } - - //--- default - return base.VisitMethodCall(expression); } - #endregion + return base.VisitBinary(expression); + } - #region Helpers - /// - /// Builds and/or. - /// - /// - private void BuildAndOr(BinaryExpression expression) + /// + /// Scans the children of . + /// + /// Target expression + /// + protected override Expression VisitMethodCall(MethodCallExpression expression) + { + //--- bool Contains(T value) + if (expression.Method.Name == nameof(Enumerable.Contains)) { - ref var builder = ref Unsafe.AsRef(this.stringBuilderPointer); - var @operator = OperatorExtensions.From(expression.NodeType); - - //--- left - var leftOperator = OperatorExtensions.From(expression.Left.NodeType); - if (NeedsBracket(@operator, leftOperator)) + var t = expression.Method.DeclaringType; + if (t == typeof(Enumerable)) { - builder.Append('('); - this.Visit(expression.Left); - builder.Append(')'); + this.BuildInClause(expression, true); } - else + else if (t?.Namespace?.StartsWith("System.Collections") ?? false) { - this.Visit(expression.Left); + this.BuildInClause(expression, false); } + } - //--- and / or - if (@operator == Operator.AndAlso) builder.Append(" and "); - if (@operator == Operator.OrElse) builder.Append(" or "); + //--- default + return base.VisitMethodCall(expression); + } + #endregion - //--- right - var rightOperator = OperatorExtensions.From(expression.Right.NodeType); - if (NeedsBracket(@operator, rightOperator)) - { - builder.Append('('); - this.Visit(expression.Right); - builder.Append(')'); - } - else - { - this.Visit(expression.Right); - } - #region Local Functions - static bool NeedsBracket(Operator self, Operator side) - => (self != side) && (side == Operator.AndAlso || side == Operator.OrElse); - #endregion + #region Helpers + /// + /// Builds and/or. + /// + /// + private void BuildAndOr(BinaryExpression expression) + { + ref var builder = ref Unsafe.AsRef(this.stringBuilderPointer); + var @operator = OperatorExtensions.From(expression.NodeType); + + //--- left + var leftOperator = OperatorExtensions.From(expression.Left.NodeType); + if (NeedsBracket(@operator, leftOperator)) + { + builder.Append('('); + this.Visit(expression.Left); + builder.Append(')'); + } + else + { + this.Visit(expression.Left); } + //--- and / or + if (@operator == Operator.AndAlso) builder.Append(" and "); + if (@operator == Operator.OrElse) builder.Append(" or "); - /// - /// Builds binary. - /// - /// - /// - /// - private void BuildBinary(Operator @operator, string propertyName, object? value) + //--- right + var rightOperator = OperatorExtensions.From(expression.Right.NodeType); + if (NeedsBracket(@operator, rightOperator)) { - ref var builder = ref Unsafe.AsRef(this.stringBuilderPointer); - ref var bindParameter = ref Unsafe.AsRef(this.bindParameterPointer); - - //--- Build sql - var bracket = this.dbProvider.KeywordBracket; - var columnName = table.ColumnsByMemberName[propertyName].ColumnName; - builder.Append(bracket.Begin); - builder.Append(columnName); - builder.Append(bracket.End); + builder.Append('('); + this.Visit(expression.Right); + builder.Append(')'); + } + else + { + this.Visit(expression.Right); + } - switch (@operator) - { - case Operator.Equal: - if (value is null) - { - builder.Append(" is null"); - return; - } - builder.Append(" = "); - break; + #region Local Functions + static bool NeedsBracket(Operator self, Operator side) + => (self != side) && (side == Operator.AndAlso || side == Operator.OrElse); + #endregion + } - case Operator.NotEqual: - if (value is null) - { - builder.Append(" is not null"); - return; - } - builder.Append(" <> "); - break; - case Operator.LessThan: - builder.Append(" < "); - break; + /// + /// Builds binary. + /// + /// + /// + /// + private void BuildBinary(Operator @operator, string propertyName, object? value) + { + ref var builder = ref Unsafe.AsRef(this.stringBuilderPointer); + ref var bindParameter = ref Unsafe.AsRef(this.bindParameterPointer); - case Operator.LessThanOrEqual: - builder.Append(" <= "); - break; + //--- Build sql + var bracket = this.dbProvider.KeywordBracket; + var columnName = table.ColumnsByMemberName[propertyName].ColumnName; + builder.Append(bracket.Begin); + builder.Append(columnName); + builder.Append(bracket.End); - case Operator.GreaterThan: - builder.Append(" > "); - break; + switch (@operator) + { + case Operator.Equal: + if (value is null) + { + builder.Append(" is null"); + return; + } + builder.Append(" = "); + break; - case Operator.GreaterThanOrEqual: - builder.Append(" >= "); - break; + case Operator.NotEqual: + if (value is null) + { + builder.Append(" is not null"); + return; + } + builder.Append(" <> "); + break; - case Operator.Contains: - builder.Append(" in "); - break; + case Operator.LessThan: + builder.Append(" < "); + break; - default: - throw new InvalidOperationException(); - } + case Operator.LessThanOrEqual: + builder.Append(" <= "); + break; - //--- Cache parameter - bindParameter ??= new BindParameter(); - var name = ZString.Concat('p', bindParameter.Count + 1); - bindParameter.Add(name, value); - builder.Append(this.dbProvider.BindParameterPrefix); - builder.Append(name); - } + case Operator.GreaterThan: + builder.Append(" > "); + break; + case Operator.GreaterThanOrEqual: + builder.Append(" >= "); + break; - /// - /// Build in clause. - /// - /// - /// - private void BuildInClause(MethodCallExpression expression, bool isExtensionMethod) - { - //--- Gets property name - var argExpression = isExtensionMethod ? expression.Arguments[1] : expression.Arguments[0]; - var propertyName = this.ExtractMemberName(argExpression); - if (propertyName is null) - throw new InvalidOperationException(); + case Operator.Contains: + builder.Append(" in "); + break; - //--- Generates element - //--- If there are more than 1000 in clauses, error will occur. - var objExpression = isExtensionMethod ? expression.Arguments[0] : expression.Object; - if (objExpression is null) + default: throw new InvalidOperationException(); + } - var elements = this.ExtractValue(objExpression) as IEnumerable; - if (elements is null) - throw new InvalidOperationException(); + //--- Cache parameter + bindParameter ??= new BindParameter(); + var name = ZString.Concat('p', bindParameter.Count + 1); + bindParameter.Add(name, value); + builder.Append(this.dbProvider.BindParameterPrefix); + builder.Append(name); + } - var source - = elements - .Cast() - .Buffer(SqlConstants.InClauseUpperLimitCount) - .ToArray(); - //--- Build sql - ref var builder = ref Unsafe.AsRef(this.stringBuilderPointer); - if (source.Length == 0) - { - //--- There is no element in the in clause, it is forced to false. - this.BuildBoolean(false); - } - else if (source.Length == 1) - { - var x = source[0]; - this.BuildBinary(Operator.Contains, propertyName, x); - } - else + /// + /// Build in clause. + /// + /// + /// + private void BuildInClause(MethodCallExpression expression, bool isExtensionMethod) + { + //--- Gets property name + var argExpression = isExtensionMethod ? expression.Arguments[1] : expression.Arguments[0]; + var propertyName = this.ExtractMemberName(argExpression); + if (propertyName is null) + throw new InvalidOperationException(); + + //--- Generates element + //--- If there are more than 1000 in clauses, error will occur. + var objExpression = isExtensionMethod ? expression.Arguments[0] : expression.Object; + if (objExpression is null) + throw new InvalidOperationException(); + + var elements = this.ExtractValue(objExpression) as IEnumerable; + if (elements is null) + throw new InvalidOperationException(); + + var source + = elements + .Cast() + .Buffer(SqlConstants.InClauseUpperLimitCount) + .ToArray(); + + //--- Build sql + ref var builder = ref Unsafe.AsRef(this.stringBuilderPointer); + if (source.Length == 0) + { + //--- There is no element in the in clause, it is forced to false. + this.BuildBoolean(false); + } + else if (source.Length == 1) + { + var x = source[0]; + this.BuildBinary(Operator.Contains, propertyName, x); + } + else + { + builder.Append('('); + for (var i = 0; i < source.Length; i++) { - builder.Append('('); - for (var i = 0; i < source.Length; i++) - { - if (i > 0) - builder.Append(" or "); - this.BuildBinary(Operator.Contains, propertyName, source[i]); - } - builder.Append(')'); + if (i > 0) + builder.Append(" or "); + this.BuildBinary(Operator.Contains, propertyName, source[i]); } + builder.Append(')'); } + } - /// - /// Builds boolean. - /// - /// - private void BuildBoolean(bool value) - { - ref var builder = ref Unsafe.AsRef(this.stringBuilderPointer); - var sql = value ? "1 = 1" : "1 = 0"; - builder.Append(sql); - } + /// + /// Builds boolean. + /// + /// + private void BuildBoolean(bool value) + { + ref var builder = ref Unsafe.AsRef(this.stringBuilderPointer); + var sql = value ? "1 = 1" : "1 = 0"; + builder.Append(sql); + } - /// - /// Extracts the member name from the specified expression. - /// - /// - /// - private string? ExtractMemberName(Expression expression) - { - var member = ExpressionHelper.ExtractMemberExpression(expression); - return member?.Expression == this.parameter - ? member.Member.Name - : null; - } + /// + /// Extracts the member name from the specified expression. + /// + /// + /// + private string? ExtractMemberName(Expression expression) + { + var member = ExpressionHelper.ExtractMemberExpression(expression); + return member?.Expression == this.parameter + ? member.Member.Name + : null; + } - /// - /// Extracts the value from the specified expression. - /// - /// - /// - /// Please use only for right node. - private object? ExtractValue(Expression expression) - { - //--- Constant - if (expression is ConstantExpression constant) - return constant.Value; + /// + /// Extracts the value from the specified expression. + /// + /// + /// + /// Please use only for right node. + private object? ExtractValue(Expression expression) + { + //--- Constant + if (expression is ConstantExpression constant) + return constant.Value; - //--- Creates instance - if (expression is NewExpression @new) - { - var parameters = @new.Arguments.Select(this.ExtractValue).ToArray(); - return @new.Constructor?.Invoke(parameters); - } + //--- Creates instance + if (expression is NewExpression @new) + { + var parameters = @new.Arguments.Select(this.ExtractValue).ToArray(); + return @new.Constructor?.Invoke(parameters); + } - //--- new T[] - if (expression is NewArrayExpression newArray) - { - return newArray.Expressions.Select(this.ExtractValue).ToArray(); - } + //--- new T[] + if (expression is NewArrayExpression newArray) + { + return newArray.Expressions.Select(this.ExtractValue).ToArray(); + } - //--- Method call - if (expression is MethodCallExpression methodCall) - { - var parameters = methodCall.Arguments.Select(this.ExtractValue).ToArray(); - var obj = methodCall.Object is null - ? null // static - : this.ExtractValue(methodCall.Object); // instance - return methodCall.Method.Invoke(obj, parameters); - } + //--- Method call + if (expression is MethodCallExpression methodCall) + { + var parameters = methodCall.Arguments.Select(this.ExtractValue).ToArray(); + var obj = methodCall.Object is null + ? null // static + : this.ExtractValue(methodCall.Object); // instance + return methodCall.Method.Invoke(obj, parameters); + } - //--- Delegate / Lambda - if (expression is InvocationExpression invocation) - { - var parameters = invocation.Arguments.Select(x => Expression.Parameter(x.Type)).ToArray(); - var arguments = invocation.Arguments.Select(this.ExtractValue).ToArray(); - var lambda = Expression.Lambda(invocation, parameters); - var result = lambda.Compile().DynamicInvoke(arguments); - return result; - } + //--- Delegate / Lambda + if (expression is InvocationExpression invocation) + { + var parameters = invocation.Arguments.Select(x => Expression.Parameter(x.Type)).ToArray(); + var arguments = invocation.Arguments.Select(this.ExtractValue).ToArray(); + var lambda = Expression.Lambda(invocation, parameters); + var result = lambda.Compile().DynamicInvoke(arguments); + return result; + } - //--- Indexer - if (expression is BinaryExpression binary) + //--- Indexer + if (expression is BinaryExpression binary) if (expression.NodeType == ExpressionType.ArrayIndex) { var array = (Array)this.ExtractValue(binary.Left)!; @@ -431,142 +431,141 @@ private void BuildBoolean(bool value) return array.GetValue(index); } - //--- Field / Property - var memberNames = new List(); - var temp = expression; - while (!(temp is ConstantExpression)) - { - //--- cast - if (temp is UnaryExpression unary) + //--- Field / Property + var memberNames = new List(); + var temp = expression; + while (!(temp is ConstantExpression)) + { + //--- cast + if (temp is UnaryExpression unary) if (temp.NodeType == ExpressionType.Convert) { temp = unary.Operand; continue; } - //--- not member - if (temp is not MemberExpression member) - return this.ExtractValue(temp); + //--- not member + if (temp is not MemberExpression member) + return this.ExtractValue(temp); - //--- static - if (member.Expression is null) - { - if (member.Member is PropertyInfo pi) return pi.GetValue(null); - if (member.Member is FieldInfo fi) return fi.GetValue(null); - throw new InvalidOperationException("Not field or property."); - } - - //--- instance - memberNames.Add(member.Member.Name); - temp = member.Expression; + //--- static + if (member.Expression is null) + { + if (member.Member is PropertyInfo pi) return pi.GetValue(null); + if (member.Member is FieldInfo fi) return fi.GetValue(null); + throw new InvalidOperationException("Not field or property."); } - var value = ((ConstantExpression)temp).Value; - for (int i = memberNames.Count - 1; 0 <= i; i--) - value = ObjectAccessor.Create(value)[memberNames[i]]; - return value; + //--- instance + memberNames.Add(member.Member.Name); + temp = member.Expression; } - #endregion + + var value = ((ConstantExpression)temp).Value; + for (int i = memberNames.Count - 1; 0 <= i; i--) + value = ObjectAccessor.Create(value)[memberNames[i]]; + return value; } + #endregion + } + /// + /// Represents a conditional expression operator. + /// + private enum Operator + { /// - /// Represents a conditional expression operator. + /// Unknown /// - private enum Operator - { - /// - /// Unknown - /// - Unknown = 0, - - /// - /// a && b - /// - AndAlso, - - /// - /// a || b - /// - OrElse, - - /// - /// a < b - /// - LessThan, - - /// - /// a <= b - /// - LessThanOrEqual, - - /// - /// a > b - /// - GreaterThan, - - /// - /// a >= b - /// - GreaterThanOrEqual, - - /// - /// a == b - /// - Equal, - - /// - /// a != b - /// - NotEqual, - - /// - /// Enumerable.Contains(value) - /// - Contains, - } + Unknown = 0, + /// + /// a && b + /// + AndAlso, /// - /// Provides helper methods. + /// a || b /// - private static class OperatorExtensions - { - /// - /// Converts from to . - /// - /// - /// - public static Operator From(ExpressionType expressionType) - => expressionType switch - { - ExpressionType.AndAlso => Operator.AndAlso, - ExpressionType.OrElse => Operator.OrElse, - ExpressionType.LessThan => Operator.LessThan, - ExpressionType.LessThanOrEqual => Operator.LessThanOrEqual, - ExpressionType.GreaterThan => Operator.GreaterThan, - ExpressionType.GreaterThanOrEqual => Operator.GreaterThanOrEqual, - ExpressionType.Equal => Operator.Equal, - ExpressionType.NotEqual => Operator.NotEqual, - _ => Operator.Unknown, - }; - - - /// - /// Inverts the specified operator. - /// - /// - /// - public static Operator Flip(Operator @operator) - => @operator switch - { - Operator.LessThan => Operator.GreaterThan, - Operator.LessThanOrEqual => Operator.GreaterThanOrEqual, - Operator.GreaterThan => Operator.LessThan, - Operator.GreaterThanOrEqual => Operator.LessThanOrEqual, - _ => @operator, - }; - } - #endregion + OrElse, + + /// + /// a < b + /// + LessThan, + + /// + /// a <= b + /// + LessThanOrEqual, + + /// + /// a > b + /// + GreaterThan, + + /// + /// a >= b + /// + GreaterThanOrEqual, + + /// + /// a == b + /// + Equal, + + /// + /// a != b + /// + NotEqual, + + /// + /// Enumerable.Contains(value) + /// + Contains, + } + + + /// + /// Provides helper methods. + /// + private static class OperatorExtensions + { + /// + /// Converts from to . + /// + /// + /// + public static Operator From(ExpressionType expressionType) + => expressionType switch + { + ExpressionType.AndAlso => Operator.AndAlso, + ExpressionType.OrElse => Operator.OrElse, + ExpressionType.LessThan => Operator.LessThan, + ExpressionType.LessThanOrEqual => Operator.LessThanOrEqual, + ExpressionType.GreaterThan => Operator.GreaterThan, + ExpressionType.GreaterThanOrEqual => Operator.GreaterThanOrEqual, + ExpressionType.Equal => Operator.Equal, + ExpressionType.NotEqual => Operator.NotEqual, + _ => Operator.Unknown, + }; + + + /// + /// Inverts the specified operator. + /// + /// + /// + public static Operator Flip(Operator @operator) + => @operator switch + { + Operator.LessThan => Operator.GreaterThan, + Operator.LessThanOrEqual => Operator.GreaterThanOrEqual, + Operator.GreaterThan => Operator.LessThan, + Operator.GreaterThanOrEqual => Operator.LessThanOrEqual, + _ => @operator, + }; } + #endregion } diff --git a/src/DeclarativeSql/Sql/Query.cs b/src/DeclarativeSql/Sql/Query.cs index 9f01d20..f0f88e6 100644 --- a/src/DeclarativeSql/Sql/Query.cs +++ b/src/DeclarativeSql/Sql/Query.cs @@ -1,36 +1,37 @@ -namespace DeclarativeSql.Sql +namespace DeclarativeSql.Sql; + + + +/// +/// Represents a query statement and parameter pair. +/// +public readonly struct Query { + #region Properties /// - /// Represents a query statement and parameter pair. + /// Gets SQL statement. /// - public readonly struct Query - { - #region Properties - /// - /// Gets SQL statement. - /// - public string Statement { get; } + public string Statement { get; } - /// - /// Gets bind parameter collection. - /// This contains parameters that are generated by where clause. - /// - public BindParameter? BindParameter { get; } - #endregion + /// + /// Gets bind parameter collection. + /// This contains parameters that are generated by where clause. + /// + public BindParameter? BindParameter { get; } + #endregion - #region Constructors - /// - /// Creates instance. - /// - /// - /// - internal Query(string statement, BindParameter? bindParameter) - { - this.Statement = statement; - this.BindParameter = bindParameter; - } - #endregion + #region Constructors + /// + /// Creates instance. + /// + /// + /// + internal Query(string statement, BindParameter? bindParameter) + { + this.Statement = statement; + this.BindParameter = bindParameter; } + #endregion } diff --git a/src/DeclarativeSql/Sql/QueryBuilder.cs b/src/DeclarativeSql/Sql/QueryBuilder.cs index cdf1582..892cc35 100644 --- a/src/DeclarativeSql/Sql/QueryBuilder.cs +++ b/src/DeclarativeSql/Sql/QueryBuilder.cs @@ -5,535 +5,534 @@ using DeclarativeSql.Sql.Clauses; using DeclarativeSql.Sql.Statements; +namespace DeclarativeSql.Sql; -namespace DeclarativeSql.Sql + +/// +/// Provides query builder. +/// +public ref struct QueryBuilder //: IDisposable { + #region Fields + private readonly DbProvider dbProvider; + private readonly TableInfo table; + private Utf16ValueStringBuilder stringBuilder; + private BindParameter? bindParameter; + #endregion + + + #region Constructors /// - /// Provides query builder. + /// Creates instance. /// - public ref struct QueryBuilder //: IDisposable + /// + /// This instance must be call method after . + public QueryBuilder(DbProvider provider) { - #region Fields - private readonly DbProvider dbProvider; - private readonly TableInfo table; - private Utf16ValueStringBuilder stringBuilder; - private BindParameter? bindParameter; - #endregion - - - #region Constructors - /// - /// Creates instance. - /// - /// - /// This instance must be call method after . - public QueryBuilder(DbProvider provider) - { - this.dbProvider = provider; - this.table = TableInfo.Get(provider.Database); - this.stringBuilder = ZString.CreateStringBuilder(); - this.bindParameter = null; - } - #endregion + this.dbProvider = provider; + this.table = TableInfo.Get(provider.Database); + this.stringBuilder = ZString.CreateStringBuilder(); + this.bindParameter = null; + } + #endregion - #region IDisposable implementations - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - => this.stringBuilder.Dispose(); - #endregion + #region IDisposable implementations + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + => this.stringBuilder.Dispose(); + #endregion - /// - /// Build query up. - /// - /// - public Query Build() - { - var statement = this.stringBuilder.ToString(); - return new Query(statement, this.bindParameter); - } + /// + /// Build query up. + /// + /// + public Query Build() + { + var statement = this.stringBuilder.ToString(); + return new Query(statement, this.bindParameter); + } - #region Statements - /// - /// Builds count statement. - /// - /// - public void Count() - { - this.AppendLineIfNotEmpty(); - var x = new Count(); - x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); - } + #region Statements + /// + /// Builds count statement. + /// + /// + public void Count() + { + this.AppendLineIfNotEmpty(); + var x = new Count(); + x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); + } - /// - /// Builds select statement. - /// - /// - /// - public void Select(Expression>? properties = null) - { - this.AppendLineIfNotEmpty(); - var x = new Select(properties); - x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); - } + /// + /// Builds select statement. + /// + /// + /// + public void Select(Expression>? properties = null) + { + this.AppendLineIfNotEmpty(); + var x = new Select(properties); + x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); + } - /// - /// Builds insert statement. - /// - /// - /// - public void Insert(ValuePriority createdAtPriority = default) - { - this.AppendLineIfNotEmpty(); - var x = new Insert(createdAtPriority); - x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); - } + /// + /// Builds insert statement. + /// + /// + /// + public void Insert(ValuePriority createdAtPriority = default) + { + this.AppendLineIfNotEmpty(); + var x = new Insert(createdAtPriority); + x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); + } - /// - /// Builds upadte statement. - /// - /// - /// - /// - public void Update(Expression>? properties = null, ValuePriority modifiedAtPriority = default) - { - this.AppendLineIfNotEmpty(); - var x = new Update(properties, modifiedAtPriority); - x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); - } + /// + /// Builds upadte statement. + /// + /// + /// + /// + public void Update(Expression>? properties = null, ValuePriority modifiedAtPriority = default) + { + this.AppendLineIfNotEmpty(); + var x = new Update(properties, modifiedAtPriority); + x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); + } - /// - /// Builds delete statement. - /// - /// - public void Delete() - { - this.AppendLineIfNotEmpty(); - var x = new Delete(); - x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); - } + /// + /// Builds delete statement. + /// + /// + public void Delete() + { + this.AppendLineIfNotEmpty(); + var x = new Delete(); + x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); + } - /// - /// Builds truncate statement. - /// - /// - public void Truncate() - { - this.AppendLineIfNotEmpty(); - var x = new Truncate(); - x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); - } - #endregion + /// + /// Builds truncate statement. + /// + /// + public void Truncate() + { + this.AppendLineIfNotEmpty(); + var x = new Truncate(); + x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); + } + #endregion - #region Clauses - /// - /// Builds where clause. - /// - /// - /// - public void Where(Expression> predicate) - { - this.AppendLineIfNotEmpty(); - var x = new Where(predicate); - x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); - } + #region Clauses + /// + /// Builds where clause. + /// + /// + /// + public void Where(Expression> predicate) + { + this.AppendLineIfNotEmpty(); + var x = new Where(predicate); + x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); + } - /// - /// Builds ascending order by clause. - /// - /// - /// - public void OrderBy(Expression> property) - { - this.AppendLineIfNotEmpty(); - var x = new OrderBy(property, true); - x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); - } + /// + /// Builds ascending order by clause. + /// + /// + /// + public void OrderBy(Expression> property) + { + this.AppendLineIfNotEmpty(); + var x = new OrderBy(property, true); + x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); + } - /// - /// Builds descending order by clause. - /// - /// - /// - public void OrderByDescending(Expression> property) - { - this.AppendLineIfNotEmpty(); - var x = new OrderBy(property, false); - x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); - } + /// + /// Builds descending order by clause. + /// + /// + /// + public void OrderByDescending(Expression> property) + { + this.AppendLineIfNotEmpty(); + var x = new OrderBy(property, false); + x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); + } - /// - /// Builds ascending then by clause. - /// - /// - /// - public void ThenBy(Expression> property) - { - this.AppendLineIfNotEmpty(','); - var x = new ThenBy(property, true); - x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); - } + /// + /// Builds ascending then by clause. + /// + /// + /// + public void ThenBy(Expression> property) + { + this.AppendLineIfNotEmpty(','); + var x = new ThenBy(property, true); + x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); + } - /// - /// Builds descending then by clause. - /// - /// - /// - public void ThenByDescending(Expression> property) - { - this.AppendLineIfNotEmpty(','); - var x = new ThenBy(property, false); - x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); - } - #endregion + /// + /// Builds descending then by clause. + /// + /// + /// + public void ThenByDescending(Expression> property) + { + this.AppendLineIfNotEmpty(','); + var x = new ThenBy(property, false); + x.Build(this.dbProvider, this.table, ref this.stringBuilder, ref this.bindParameter); + } + #endregion - #region Helpers - /// - /// Appends the string representation of a specified value to this instance. - /// - /// - /// - internal void Append(U value) - => this.stringBuilder.Append(value); + #region Helpers + /// + /// Appends the string representation of a specified value to this instance. + /// + /// + /// + internal void Append(U value) + => this.stringBuilder.Append(value); - /// - /// Append default line terminator to the end. - /// - internal void AppendLine() - => this.stringBuilder.AppendLine(); + /// + /// Append default line terminator to the end. + /// + internal void AppendLine() + => this.stringBuilder.AppendLine(); - /// - /// Appends the string representation of a specified value followed by the default line terminator to the end of this instance. - /// - /// - /// - internal void AppendLine(U value) - => this.stringBuilder.AppendLine(value); + /// + /// Appends the string representation of a specified value followed by the default line terminator to the end of this instance. + /// + /// + /// + internal void AppendLine(U value) + => this.stringBuilder.AppendLine(value); - /// - /// Append default line terminator to the end, if statement isn't empty. - /// - private void AppendLineIfNotEmpty() - { - if (this.stringBuilder.Length > 0) - this.stringBuilder.AppendLine(); - } + /// + /// Append default line terminator to the end, if statement isn't empty. + /// + private void AppendLineIfNotEmpty() + { + if (this.stringBuilder.Length > 0) + this.stringBuilder.AppendLine(); + } - /// - /// Appends the string representation of a specified value followed by the default line terminator to the end of this instance, if statement isn't empty. - /// - private void AppendLineIfNotEmpty(char value) - { - if (this.stringBuilder.Length > 0) - this.stringBuilder.AppendLine(value); - } - #endregion + /// + /// Appends the string representation of a specified value followed by the default line terminator to the end of this instance, if statement isn't empty. + /// + private void AppendLineIfNotEmpty(char value) + { + if (this.stringBuilder.Length > 0) + this.stringBuilder.AppendLine(value); } + #endregion +} +/// +/// Provides query builder. +/// +public static class QueryBuilder +{ + #region Count /// - /// Provides query builder. + /// Builds count statement. /// - public static class QueryBuilder + /// + /// + /// + public static Query Count(DbProvider dbProvider) { - #region Count - /// - /// Builds count statement. - /// - /// - /// - /// - public static Query Count(DbProvider dbProvider) + using (var builder = new QueryBuilder(dbProvider)) { - using (var builder = new QueryBuilder(dbProvider)) - { - builder.Count(); - return builder.Build(); - } + builder.Count(); + return builder.Build(); } + } - /// - /// Builds count + where statement. - /// - /// - /// - /// - /// - public static Query Count(DbProvider dbProvider, Expression> predicate) + /// + /// Builds count + where statement. + /// + /// + /// + /// + /// + public static Query Count(DbProvider dbProvider, Expression> predicate) + { + using (var builder = new QueryBuilder(dbProvider)) { - using (var builder = new QueryBuilder(dbProvider)) - { - builder.Count(); - builder.Where(predicate); - return builder.Build(); - } + builder.Count(); + builder.Where(predicate); + return builder.Build(); } - #endregion - - - #region Select - /// - /// Builds select statement. - /// - /// - /// - /// - /// - public static Query Select(DbProvider dbProvider, Expression>? properties = null) + } + #endregion + + + #region Select + /// + /// Builds select statement. + /// + /// + /// + /// + /// + public static Query Select(DbProvider dbProvider, Expression>? properties = null) + { + using (var builder = new QueryBuilder(dbProvider)) { - using (var builder = new QueryBuilder(dbProvider)) - { - builder.Select(properties); - return builder.Build(); - } + builder.Select(properties); + return builder.Build(); } + } - /// - /// Builds select + where statement. - /// - /// - /// - /// - /// - /// - public static Query Select(DbProvider dbProvider, Expression> predicate, Expression>? properties = null) + /// + /// Builds select + where statement. + /// + /// + /// + /// + /// + /// + public static Query Select(DbProvider dbProvider, Expression> predicate, Expression>? properties = null) + { + using (var builder = new QueryBuilder(dbProvider)) { - using (var builder = new QueryBuilder(dbProvider)) - { - builder.Select(properties); - builder.Where(predicate); - return builder.Build(); - } + builder.Select(properties); + builder.Where(predicate); + return builder.Build(); } - #endregion - - - #region Insert - /// - /// Builds insert statement. - /// - /// - /// - /// - /// - public static Query Insert(DbProvider dbProvider, ValuePriority createdAtPriority = default) + } + #endregion + + + #region Insert + /// + /// Builds insert statement. + /// + /// + /// + /// + /// + public static Query Insert(DbProvider dbProvider, ValuePriority createdAtPriority = default) + { + using (var builder = new QueryBuilder(dbProvider)) { - using (var builder = new QueryBuilder(dbProvider)) - { - builder.Insert(createdAtPriority); - return builder.Build(); - } + builder.Insert(createdAtPriority); + return builder.Build(); } - #endregion - - - #region Update - /// - /// Builds update statement. - /// - /// - /// - /// - /// - /// - public static Query Update(DbProvider dbProvider, Expression>? properties = null, ValuePriority modifiedAt = default) + } + #endregion + + + #region Update + /// + /// Builds update statement. + /// + /// + /// + /// + /// + /// + public static Query Update(DbProvider dbProvider, Expression>? properties = null, ValuePriority modifiedAt = default) + { + using (var builder = new QueryBuilder(dbProvider)) { - using (var builder = new QueryBuilder(dbProvider)) - { - builder.Update(properties, modifiedAt); - return builder.Build(); - } + builder.Update(properties, modifiedAt); + return builder.Build(); } + } - /// - /// Builds update + where statement. - /// - /// - /// - /// - /// - /// - /// - public static Query Update(DbProvider dbProvider, Expression> predicate, Expression>? properties = null, ValuePriority modifiedAt = default) + /// + /// Builds update + where statement. + /// + /// + /// + /// + /// + /// + /// + public static Query Update(DbProvider dbProvider, Expression> predicate, Expression>? properties = null, ValuePriority modifiedAt = default) + { + using (var builder = new QueryBuilder(dbProvider)) { - using (var builder = new QueryBuilder(dbProvider)) - { - builder.Update(properties, modifiedAt); - builder.Where(predicate); - return builder.Build(); - } + builder.Update(properties, modifiedAt); + builder.Where(predicate); + return builder.Build(); } - #endregion + } + #endregion - #region Delete - /// - /// Builds delete statement. - /// - /// - /// - /// - public static Query Delete(DbProvider dbProvider) + #region Delete + /// + /// Builds delete statement. + /// + /// + /// + /// + public static Query Delete(DbProvider dbProvider) + { + using (var builder = new QueryBuilder(dbProvider)) { - using (var builder = new QueryBuilder(dbProvider)) - { - builder.Delete(); - return builder.Build(); - } + builder.Delete(); + return builder.Build(); } + } - /// - /// Builds delete + where statement. - /// - /// - /// - /// - /// - public static Query Delete(DbProvider dbProvider, Expression> predicate) + /// + /// Builds delete + where statement. + /// + /// + /// + /// + /// + public static Query Delete(DbProvider dbProvider, Expression> predicate) + { + using (var builder = new QueryBuilder(dbProvider)) { - using (var builder = new QueryBuilder(dbProvider)) - { - builder.Delete(); - builder.Where(predicate); - return builder.Build(); - } + builder.Delete(); + builder.Where(predicate); + return builder.Build(); } - #endregion + } + #endregion - #region Truncate - /// - /// Builds truncate statement. - /// - /// - /// - /// - public static Query Truncate(DbProvider dbProvider) + #region Truncate + /// + /// Builds truncate statement. + /// + /// + /// + /// + public static Query Truncate(DbProvider dbProvider) + { + using (var builder = new QueryBuilder(dbProvider)) { - using (var builder = new QueryBuilder(dbProvider)) - { - builder.Truncate(); - return builder.Build(); - } + builder.Truncate(); + return builder.Build(); } - #endregion - - - #region Where - /// - /// Builds where clause. - /// - /// - /// - /// - /// - public static Query Where(DbProvider dbProvider, Expression> predicate) + } + #endregion + + + #region Where + /// + /// Builds where clause. + /// + /// + /// + /// + /// + public static Query Where(DbProvider dbProvider, Expression> predicate) + { + using (var builder = new QueryBuilder(dbProvider)) { - using (var builder = new QueryBuilder(dbProvider)) - { - builder.Where(predicate); - return builder.Build(); - } + builder.Where(predicate); + return builder.Build(); } - #endregion - - - #region OrderBy - /// - /// Builds ascending order by clause. - /// - /// - /// - /// - /// - public static Query OrderBy(DbProvider dbProvider, Expression> property) + } + #endregion + + + #region OrderBy + /// + /// Builds ascending order by clause. + /// + /// + /// + /// + /// + public static Query OrderBy(DbProvider dbProvider, Expression> property) + { + using (var builder = new QueryBuilder(dbProvider)) { - using (var builder = new QueryBuilder(dbProvider)) - { - builder.OrderBy(property); - return builder.Build(); - } + builder.OrderBy(property); + return builder.Build(); } + } - /// - /// Builds descending order by clause. - /// - /// - /// - /// - /// - public static Query OrderByDescending(DbProvider dbProvider, Expression> property) + /// + /// Builds descending order by clause. + /// + /// + /// + /// + /// + public static Query OrderByDescending(DbProvider dbProvider, Expression> property) + { + using (var builder = new QueryBuilder(dbProvider)) { - using (var builder = new QueryBuilder(dbProvider)) - { - builder.OrderByDescending(property); - return builder.Build(); - } + builder.OrderByDescending(property); + return builder.Build(); } - #endregion - - - /* - #region ThenBy - /// - /// Builds ascending then by clause. - /// - /// - /// - /// - /// - public static Query ThenBy(DbProvider dbProvider, Expression> property) + } + #endregion + + + /* + #region ThenBy + /// + /// Builds ascending then by clause. + /// + /// + /// + /// + /// + public static Query ThenBy(DbProvider dbProvider, Expression> property) + { + using (var builder = new QueryBuilder(dbProvider)) { - using (var builder = new QueryBuilder(dbProvider)) - { - builder.ThenBy(property); - return builder.Build(); - } + builder.ThenBy(property); + return builder.Build(); } + } - /// - /// Builds descending then by clause. - /// - /// - /// - /// - /// - public static Query ThenByDescending(DbProvider dbProvider, Expression> property) + /// + /// Builds descending then by clause. + /// + /// + /// + /// + /// + public static Query ThenByDescending(DbProvider dbProvider, Expression> property) + { + using (var builder = new QueryBuilder(dbProvider)) { - using (var builder = new QueryBuilder(dbProvider)) - { - builder.TheThenByDescendingnBy(property); - return builder.Build(); - } + builder.TheThenByDescendingnBy(property); + return builder.Build(); } - #endregion - */ } + #endregion + */ } diff --git a/src/DeclarativeSql/Sql/Sql.cs b/src/DeclarativeSql/Sql/Sql.cs index a48bde2..7bce3b9 100644 --- a/src/DeclarativeSql/Sql/Sql.cs +++ b/src/DeclarativeSql/Sql/Sql.cs @@ -1,22 +1,21 @@ using Cysharp.Text; using DeclarativeSql.Mapping; +namespace DeclarativeSql.Sql; -namespace DeclarativeSql.Sql + +/// +/// Represents SQL. +/// +internal interface ISql { /// - /// Represents SQL. + /// Builds query. /// - internal interface ISql - { - /// - /// Builds query. - /// - /// - /// - /// - /// - void Build(DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter); - } + /// + /// + /// + /// + void Build(DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter); } diff --git a/src/DeclarativeSql/Sql/SqlConstants.cs b/src/DeclarativeSql/Sql/SqlConstants.cs index bd39640..7658307 100644 --- a/src/DeclarativeSql/Sql/SqlConstants.cs +++ b/src/DeclarativeSql/Sql/SqlConstants.cs @@ -1,14 +1,15 @@ -namespace DeclarativeSql.Sql +namespace DeclarativeSql.Sql; + + + +/// +/// Provides constants used to build SQL. +/// +internal static class SqlConstants { /// - /// Provides constants used to build SQL. + /// Represents the maximum number of elements that can be included in an in clause. + /// This is constant value. /// - internal static class SqlConstants - { - /// - /// Represents the maximum number of elements that can be included in an in clause. - /// This is constant value. - /// - public const int InClauseUpperLimitCount = 1000; - } + public const int InClauseUpperLimitCount = 1000; } diff --git a/src/DeclarativeSql/Sql/Statements/Count.cs b/src/DeclarativeSql/Sql/Statements/Count.cs index 667e803..8c5182d 100644 --- a/src/DeclarativeSql/Sql/Statements/Count.cs +++ b/src/DeclarativeSql/Sql/Statements/Count.cs @@ -1,28 +1,27 @@ using Cysharp.Text; using DeclarativeSql.Mapping; +namespace DeclarativeSql.Sql.Statements; -namespace DeclarativeSql.Sql.Statements + +/// +/// Represents count statement. +/// +/// +internal readonly struct Count : ISql { - /// - /// Represents count statement. - /// - /// - internal readonly struct Count : ISql + #region ISql implementations + /// + public void Build(DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter) { - #region ISql implementations - /// - public void Build(DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter) - { - var bracket = dbProvider.KeywordBracket; - builder.Append("select count(*) as "); - builder.Append(bracket.Begin); - builder.Append("Count"); - builder.Append(bracket.End); - builder.Append(" from "); - builder.Append(table.FullName); - } - #endregion + var bracket = dbProvider.KeywordBracket; + builder.Append("select count(*) as "); + builder.Append(bracket.Begin); + builder.Append("Count"); + builder.Append(bracket.End); + builder.Append(" from "); + builder.Append(table.FullName); } + #endregion } diff --git a/src/DeclarativeSql/Sql/Statements/Delete.cs b/src/DeclarativeSql/Sql/Statements/Delete.cs index 2173f60..99566d1 100644 --- a/src/DeclarativeSql/Sql/Statements/Delete.cs +++ b/src/DeclarativeSql/Sql/Statements/Delete.cs @@ -1,23 +1,22 @@ using Cysharp.Text; using DeclarativeSql.Mapping; +namespace DeclarativeSql.Sql.Statements; -namespace DeclarativeSql.Sql.Statements + +/// +/// Represents delete statement. +/// +/// +internal readonly struct Delete : ISql { - /// - /// Represents delete statement. - /// - /// - internal readonly struct Delete : ISql + #region ISql implementations + /// + public void Build(DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter) { - #region ISql implementations - /// - public void Build(DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter) - { - builder.Append("delete from "); - builder.Append(table.FullName); - } - #endregion + builder.Append("delete from "); + builder.Append(table.FullName); } + #endregion } diff --git a/src/DeclarativeSql/Sql/Statements/Insert.cs b/src/DeclarativeSql/Sql/Statements/Insert.cs index 52f65f1..0fcde4c 100644 --- a/src/DeclarativeSql/Sql/Statements/Insert.cs +++ b/src/DeclarativeSql/Sql/Statements/Insert.cs @@ -1,92 +1,91 @@ using Cysharp.Text; using DeclarativeSql.Mapping; +namespace DeclarativeSql.Sql.Statements; -namespace DeclarativeSql.Sql.Statements + +/// +/// Represents insert statement. +/// +/// +internal readonly struct Insert : ISql { + #region Properties /// - /// Represents insert statement. + /// Gets the value priority of CreatedAt column. /// - /// - internal readonly struct Insert : ISql - { - #region Properties - /// - /// Gets the value priority of CreatedAt column. - /// - private ValuePriority CreatedAtPriority { get; } - #endregion + private ValuePriority CreatedAtPriority { get; } + #endregion - #region Constructors - /// - /// Creates instance. - /// - /// - public Insert(ValuePriority createdAtPriority) - => this.CreatedAtPriority = createdAtPriority; - #endregion + #region Constructors + /// + /// Creates instance. + /// + /// + public Insert(ValuePriority createdAtPriority) + => this.CreatedAtPriority = createdAtPriority; + #endregion - #region ISql implementations - /// - public void Build(DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter) + #region ISql implementations + /// + public void Build(DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter) + { + var bracket = dbProvider.KeywordBracket; + var prefix = dbProvider.BindParameterPrefix; + + builder.Append("insert into "); + builder.AppendLine(table.FullName); + builder.Append("("); + foreach (var x in table.Columns) { - var bracket = dbProvider.KeywordBracket; - var prefix = dbProvider.BindParameterPrefix; + if (x.IsAutoIncrement) + continue; - builder.Append("insert into "); - builder.AppendLine(table.FullName); - builder.Append("("); - foreach (var x in table.Columns) - { - if (x.IsAutoIncrement) - continue; + builder.AppendLine(); + builder.Append(" "); + builder.Append(bracket.Begin); + builder.Append(x.ColumnName); + builder.Append(bracket.End); + builder.Append(','); + } + builder.Advance(-1); + builder.AppendLine(); + builder.AppendLine(")"); + builder.AppendLine("values"); + builder.Append("("); + foreach (var x in table.Columns) + { + if (x.IsAutoIncrement) + continue; - builder.AppendLine(); - builder.Append(" "); - builder.Append(bracket.Begin); - builder.Append(x.ColumnName); - builder.Append(bracket.End); - builder.Append(','); - } - builder.Advance(-1); builder.AppendLine(); - builder.AppendLine(")"); - builder.AppendLine("values"); - builder.Append("("); - foreach (var x in table.Columns) + builder.Append(" "); + if (this.CreatedAtPriority == ValuePriority.Default) { - if (x.IsAutoIncrement) + if (x.IsCreatedAt && x.DefaultValue is not null) + { + builder.Append(x.DefaultValue); + builder.Append(','); continue; - - builder.AppendLine(); - builder.Append(" "); - if (this.CreatedAtPriority == ValuePriority.Default) + } + if (x.IsModifiedAt && x.DefaultValue is not null) { - if (x.IsCreatedAt && x.DefaultValue is not null) - { - builder.Append(x.DefaultValue); - builder.Append(','); - continue; - } - if (x.IsModifiedAt && x.DefaultValue is not null) - { - builder.Append(x.DefaultValue); - builder.Append(','); - continue; - } + builder.Append(x.DefaultValue); + builder.Append(','); + continue; } - builder.Append(prefix); - builder.Append(x.MemberName); - builder.Append(','); - //bindParameter.Add(x.MemberName, null); } - builder.Advance(-1); - builder.AppendLine(); - builder.Append(")"); + builder.Append(prefix); + builder.Append(x.MemberName); + builder.Append(','); + //bindParameter.Add(x.MemberName, null); } - #endregion + builder.Advance(-1); + builder.AppendLine(); + builder.Append(")"); } + #endregion } diff --git a/src/DeclarativeSql/Sql/Statements/Select.cs b/src/DeclarativeSql/Sql/Statements/Select.cs index 4ab9169..f8d4f47 100644 --- a/src/DeclarativeSql/Sql/Statements/Select.cs +++ b/src/DeclarativeSql/Sql/Statements/Select.cs @@ -5,67 +5,66 @@ using DeclarativeSql.Internals; using DeclarativeSql.Mapping; +namespace DeclarativeSql.Sql.Statements; -namespace DeclarativeSql.Sql.Statements + +/// +/// Represents select statement. +/// +/// +internal readonly struct Select : ISql { + #region Properties /// - /// Represents select statement. + /// Gets the properties mapped to the column. /// - /// - internal readonly struct Select : ISql - { - #region Properties - /// - /// Gets the properties mapped to the column. - /// - private Expression>? Properties { get; } - #endregion + private Expression>? Properties { get; } + #endregion - #region Constructors - /// - /// Creates instance. - /// - /// Properties that mapped to the target column. If null, all columns are targeted. - public Select(Expression>? properties) - => this.Properties = properties; - #endregion + #region Constructors + /// + /// Creates instance. + /// + /// Properties that mapped to the target column. If null, all columns are targeted. + public Select(Expression>? properties) + => this.Properties = properties; + #endregion - #region ISql implementations - /// - public void Build(DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter) - { - //--- Extract target columns - HashSet? targetMemberNames = null; - if (this.Properties is not null) - targetMemberNames = ExpressionHelper.GetMemberNames(this.Properties); + #region ISql implementations + /// + public void Build(DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter) + { + //--- Extract target columns + HashSet? targetMemberNames = null; + if (this.Properties is not null) + targetMemberNames = ExpressionHelper.GetMemberNames(this.Properties); - //--- Builds SQL - var bracket = dbProvider.KeywordBracket; - builder.Append("select"); - foreach (var x in table.Columns) + //--- Builds SQL + var bracket = dbProvider.KeywordBracket; + builder.Append("select"); + foreach (var x in table.Columns) + { + if (targetMemberNames is null || targetMemberNames.Contains(x.MemberName)) { - if (targetMemberNames is null || targetMemberNames.Contains(x.MemberName)) - { - builder.AppendLine(); - builder.Append(" "); - builder.Append(bracket.Begin); - builder.Append(x.ColumnName); - builder.Append(bracket.End); - builder.Append(" as "); - builder.Append(bracket.Begin); - builder.Append(x.MemberName); - builder.Append(bracket.End); - builder.Append(','); - } + builder.AppendLine(); + builder.Append(" "); + builder.Append(bracket.Begin); + builder.Append(x.ColumnName); + builder.Append(bracket.End); + builder.Append(" as "); + builder.Append(bracket.Begin); + builder.Append(x.MemberName); + builder.Append(bracket.End); + builder.Append(','); } - builder.Advance(-1); //--- remove last colon. - builder.AppendLine(); - builder.Append("from "); - builder.Append(table.FullName); - } - #endregion + } + builder.Advance(-1); //--- remove last colon. + builder.AppendLine(); + builder.Append("from "); + builder.Append(table.FullName); } + #endregion } diff --git a/src/DeclarativeSql/Sql/Statements/Truncate.cs b/src/DeclarativeSql/Sql/Statements/Truncate.cs index 16730a6..be5de99 100644 --- a/src/DeclarativeSql/Sql/Statements/Truncate.cs +++ b/src/DeclarativeSql/Sql/Statements/Truncate.cs @@ -1,23 +1,22 @@ using Cysharp.Text; using DeclarativeSql.Mapping; +namespace DeclarativeSql.Sql.Statements; -namespace DeclarativeSql.Sql.Statements + +/// +/// Represents truncate statement. +/// +/// +internal readonly struct Truncate : ISql { - /// - /// Represents truncate statement. - /// - /// - internal readonly struct Truncate : ISql + #region ISql implementations + /// + public void Build(DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter) { - #region ISql implementations - /// - public void Build(DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter) - { - builder.Append("truncate table "); - builder.Append(table.FullName); - } - #endregion + builder.Append("truncate table "); + builder.Append(table.FullName); } + #endregion } diff --git a/src/DeclarativeSql/Sql/Statements/Update.cs b/src/DeclarativeSql/Sql/Statements/Update.cs index f82d976..6022b7a 100644 --- a/src/DeclarativeSql/Sql/Statements/Update.cs +++ b/src/DeclarativeSql/Sql/Statements/Update.cs @@ -5,91 +5,90 @@ using DeclarativeSql.Internals; using DeclarativeSql.Mapping; +namespace DeclarativeSql.Sql.Statements; -namespace DeclarativeSql.Sql.Statements + +/// +/// Represents update statement. +/// +/// +internal readonly struct Update : ISql { + #region Properties /// - /// Represents update statement. + /// Gets update target properties. /// - /// - internal readonly struct Update : ISql - { - #region Properties - /// - /// Gets update target properties. - /// - private Expression>? Properties { get; } + private Expression>? Properties { get; } - /// - /// Gets the value priority of ModifiedAt column. - /// - private ValuePriority ModifiedAtPriority { get; } - #endregion + /// + /// Gets the value priority of ModifiedAt column. + /// + private ValuePriority ModifiedAtPriority { get; } + #endregion - #region Constructors - /// - /// Creates instance. - /// - /// Update target properties - /// - public Update(Expression>? properties, ValuePriority modifiedAtPriority) - { - this.Properties = properties; - this.ModifiedAtPriority = modifiedAtPriority; - } - #endregion + #region Constructors + /// + /// Creates instance. + /// + /// Update target properties + /// + public Update(Expression>? properties, ValuePriority modifiedAtPriority) + { + this.Properties = properties; + this.ModifiedAtPriority = modifiedAtPriority; + } + #endregion - #region ISql implementations - /// - public void Build(DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter) + #region ISql implementations + /// + public void Build(DbProvider dbProvider, TableInfo table, ref Utf16ValueStringBuilder builder, ref BindParameter? bindParameter) + { + //--- Extract update target columns + HashSet? targetMemberNames = null; + if (this.Properties is not null) + targetMemberNames = ExpressionHelper.GetMemberNames(this.Properties); + + //--- Build SQL + var bracket = dbProvider.KeywordBracket; + var prefix = dbProvider.BindParameterPrefix; + builder.Append("update "); + builder.AppendLine(table.FullName); + builder.Append("set"); + foreach (var x in table.Columns) { - //--- Extract update target columns - HashSet? targetMemberNames = null; - if (this.Properties is not null) - targetMemberNames = ExpressionHelper.GetMemberNames(this.Properties); + if (x.IsAutoIncrement) continue; + if (x.IsCreatedAt) continue; - //--- Build SQL - var bracket = dbProvider.KeywordBracket; - var prefix = dbProvider.BindParameterPrefix; - builder.Append("update "); - builder.AppendLine(table.FullName); - builder.Append("set"); - foreach (var x in table.Columns) + if (x.IsModifiedAt || targetMemberNames is null || targetMemberNames.Contains(x.MemberName)) { - if (x.IsAutoIncrement) continue; - if (x.IsCreatedAt) continue; - - if (x.IsModifiedAt || targetMemberNames is null || targetMemberNames.Contains(x.MemberName)) + builder.AppendLine(); + builder.Append(" "); + builder.Append(bracket.Begin); + builder.Append(x.ColumnName); + builder.Append(bracket.End); + builder.Append(" = "); + if (x.IsModifiedAt + && this.ModifiedAtPriority == ValuePriority.Default + && x.DefaultValue is not null) + { + builder.Append(x.DefaultValue); + builder.Append(','); + } + else { - builder.AppendLine(); - builder.Append(" "); - builder.Append(bracket.Begin); - builder.Append(x.ColumnName); - builder.Append(bracket.End); - builder.Append(" = "); - if (x.IsModifiedAt - && this.ModifiedAtPriority == ValuePriority.Default - && x.DefaultValue is not null) - { - builder.Append(x.DefaultValue); - builder.Append(','); - } - else - { - builder.Append(prefix); - builder.Append(x.MemberName); - builder.Append(','); - bindParameter ??= new BindParameter(); - bindParameter.Add(x.MemberName, null); - } + builder.Append(prefix); + builder.Append(x.MemberName); + builder.Append(','); + bindParameter ??= new BindParameter(); + bindParameter.Add(x.MemberName, null); } } - builder.Advance(-1); // remove last colon } - #endregion + builder.Advance(-1); // remove last colon } + #endregion } diff --git a/src/DeclarativeSql/ValuePriority.cs b/src/DeclarativeSql/ValuePriority.cs index ebc66b9..f265f78 100644 --- a/src/DeclarativeSql/ValuePriority.cs +++ b/src/DeclarativeSql/ValuePriority.cs @@ -1,19 +1,20 @@ -namespace DeclarativeSql +namespace DeclarativeSql; + + + +/// +/// Represents value priority. +/// +public enum ValuePriority { /// - /// Represents value priority. + /// Use default value if specified, then fallback to property value. /// - public enum ValuePriority - { - /// - /// Use default value if specified, then fallback to property value. - /// - Default = 0, + Default = 0, - /// - /// Use property value. - /// - Property, - } + /// + /// Use property value. + /// + Property, } From a7a67cc98e17e1e6d81f78753bf7ee26caef24d9 Mon Sep 17 00:00:00 2001 From: Takaaki Suzuki Date: Wed, 10 Nov 2021 23:39:37 +0900 Subject: [PATCH 09/10] Use pattern matching --- src/DeclarativeSql/Sql/Clauses/Where.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DeclarativeSql/Sql/Clauses/Where.cs b/src/DeclarativeSql/Sql/Clauses/Where.cs index 99c95a9..e1b90e9 100644 --- a/src/DeclarativeSql/Sql/Clauses/Where.cs +++ b/src/DeclarativeSql/Sql/Clauses/Where.cs @@ -434,7 +434,7 @@ private void BuildBoolean(bool value) //--- Field / Property var memberNames = new List(); var temp = expression; - while (!(temp is ConstantExpression)) + while (temp is not ConstantExpression) { //--- cast if (temp is UnaryExpression unary) From 6112a6c28e84db8d50be664e31507d03b59484b9 Mon Sep 17 00:00:00 2001 From: Takaaki Suzuki Date: Wed, 10 Nov 2021 23:40:03 +0900 Subject: [PATCH 10/10] Update NuGet packages --- .../DeclarativeSql.MicrosoftSqlClient.csproj | 2 +- .../DeclarativeSql.SystemSqlClient.csproj | 2 +- src/DeclarativeSql.Tests/DeclarativeSql.Tests.csproj | 4 ++-- src/DeclarativeSql/DeclarativeSql.csproj | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/DeclarativeSql.MicrosoftSqlClient/DeclarativeSql.MicrosoftSqlClient.csproj b/src/DeclarativeSql.MicrosoftSqlClient/DeclarativeSql.MicrosoftSqlClient.csproj index 438cd6b..44823e6 100644 --- a/src/DeclarativeSql.MicrosoftSqlClient/DeclarativeSql.MicrosoftSqlClient.csproj +++ b/src/DeclarativeSql.MicrosoftSqlClient/DeclarativeSql.MicrosoftSqlClient.csproj @@ -24,7 +24,7 @@ - + diff --git a/src/DeclarativeSql.SystemSqlClient/DeclarativeSql.SystemSqlClient.csproj b/src/DeclarativeSql.SystemSqlClient/DeclarativeSql.SystemSqlClient.csproj index 4dff5b6..660f49f 100644 --- a/src/DeclarativeSql.SystemSqlClient/DeclarativeSql.SystemSqlClient.csproj +++ b/src/DeclarativeSql.SystemSqlClient/DeclarativeSql.SystemSqlClient.csproj @@ -24,7 +24,7 @@ - + diff --git a/src/DeclarativeSql.Tests/DeclarativeSql.Tests.csproj b/src/DeclarativeSql.Tests/DeclarativeSql.Tests.csproj index e86f27b..01bc035 100644 --- a/src/DeclarativeSql.Tests/DeclarativeSql.Tests.csproj +++ b/src/DeclarativeSql.Tests/DeclarativeSql.Tests.csproj @@ -7,8 +7,8 @@ - - + + all diff --git a/src/DeclarativeSql/DeclarativeSql.csproj b/src/DeclarativeSql/DeclarativeSql.csproj index 3711433..1e54cee 100644 --- a/src/DeclarativeSql/DeclarativeSql.csproj +++ b/src/DeclarativeSql/DeclarativeSql.csproj @@ -24,9 +24,9 @@ - + - +