From f16d4ce804cdf1fd1d33ea3419e94d6e5f4694c0 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Mon, 6 Jun 2022 16:10:44 -0700 Subject: [PATCH 1/7] Add support of DateOnly/TimeOnly types Fix formatting Fix tests --- Directory.Build.props | 9 +- .../Sql.Drivers.Firebird/v2_5/Compiler.cs | 3 + .../Xtensive.Orm.Manual.csproj | 2 +- .../Sql.Drivers.Oracle/v09/Translator.cs | 3 + .../v8_0/ServerInfoProvider.cs | 5 + .../Xtensive.Orm.PostgreSql.csproj | 2 +- .../Sql.Drivers.SqlServer/v09/Compiler.cs | 10 + .../v09/ServerInfoProvider.cs | 7 +- .../Sql.Drivers.SqlServer/v09/Translator.cs | 9 + .../v10/ServerInfoProvider.cs | 13 +- .../Sql.Drivers.SqlServer/v10/Translator.cs | 3 + .../Xtensive.Orm.Tests.Core.csproj | 4 +- .../Xtensive.Orm.Tests.Framework.csproj | 2 +- .../Xtensive.Orm.Tests.Sql.csproj | 2 +- .../DateTime/ComparisonTest.cs | 13 +- .../DateTime/DateTimeToIsoTest.cs | 2 +- .../DateTime/DistinctTest.cs | 6 +- .../DateTime/JoinTest.cs | 8 + .../DateTime/OperationsTest.cs | 31 ++ .../DateTime/OrderByTest.cs | 7 +- .../DateTime/PartsExtractionTest.cs | 12 + .../DateTime/WhereTest.cs | 7 + .../DateTimeBaseTest.cs | 53 +-- .../Linq/DateTimeAndDateTimeOffset/Model.cs | 30 +- .../SchemaSharing/EntityManipulation/Model.cs | 10 + .../SimpleEntityManipulationTest.cs | 12 + .../Storage/SetFieldTest.cs | 10 + Orm/Xtensive.Orm/Linq/ExpressionWriter.cs | 12 + .../Orm/Linq/ExpressionExtensions.cs | 9 +- .../Orm/Linq/ItemToTupleConverter{TItem}.cs | 17 +- .../MemberCompilerProvider.cs | 20 +- .../ExpressionProcessor.Helpers.cs | 5 +- .../ExpressionTranslationHelpers.cs | 102 +++--- .../MemberCompilers/DateTimeCompilers.cs | 316 ++++++++++++------ .../Orm/Providers/SqlCompiler.Helpers.cs | 30 +- Orm/Xtensive.Orm/Reflection/WellKnownTypes.cs | 6 + .../Sql/Compiler/Internals/PostCompiler.cs | 5 +- Orm/Xtensive.Orm/Sql/Compiler/SqlCompiler.cs | 2 +- .../Sql/Compiler/SqlTranslator.cs | 12 + Orm/Xtensive.Orm/Sql/Dml/SqlFunctionType.cs | 8 + .../Sql/Info/DataTypeCollection.cs | 19 +- Orm/Xtensive.Orm/Sql/Info/ValueRange.Types.cs | 13 +- .../Sql/Internals/SqlValidator.cs | 4 + Orm/Xtensive.Orm/Sql/SqlDml.cs | 44 +++ Orm/Xtensive.Orm/Sql/SqlDriver.cs | 8 + Orm/Xtensive.Orm/Sql/SqlType.cs | 14 + .../Sql/ValueTypeMapping/TypeMapper.cs | 230 ++++++------- .../Tuples/Packed/PackedFieldAccessor.cs | 30 +- Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs | 46 ++- Orm/Xtensive.Orm/Xtensive.Orm.csproj | 2 +- 50 files changed, 840 insertions(+), 389 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 5424169cb9..2f84566bb6 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -40,7 +40,8 @@ true true - net5.0 + net5.0 + $(DO_TargetFrameworks) 9.0 $([MSBuild]::EnsureTrailingSlash( $([MSBuild]::GetDirectoryNameOfFileAbove('$(MSBuildThisFileDirectory)', 'Orm.sln')))) @@ -96,4 +97,10 @@ + + + + + $(DefineConstants);DO_DATEONLY + diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v2_5/Compiler.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v2_5/Compiler.cs index 044b637716..4b2b8c5b8c 100644 --- a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v2_5/Compiler.cs +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v2_5/Compiler.cs @@ -188,6 +188,9 @@ public override void Visit(SqlFunctionCall node) case SqlFunctionType.DateTimeAddMonths: Visit(DateAddMonth(node.Arguments[0], node.Arguments[1])); return; + case SqlFunctionType.DateOnlyAddDays: + Visit(DateAddDay(node.Arguments[0], node.Arguments[1])); + return; case SqlFunctionType.DateTimeAddYears: Visit(DateAddYear(node.Arguments[0], node.Arguments[1])); return; diff --git a/Orm/Xtensive.Orm.Manual/Xtensive.Orm.Manual.csproj b/Orm/Xtensive.Orm.Manual/Xtensive.Orm.Manual.csproj index 0855b47976..5e784f0e88 100644 --- a/Orm/Xtensive.Orm.Manual/Xtensive.Orm.Manual.csproj +++ b/Orm/Xtensive.Orm.Manual/Xtensive.Orm.Manual.csproj @@ -12,7 +12,7 @@ 2 - TRACE;DEBUG + $(DefineConstants);TRACE;DEBUG TRACE diff --git a/Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/v09/Translator.cs b/Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/v09/Translator.cs index 5c3c92167c..44832f2922 100644 --- a/Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/v09/Translator.cs +++ b/Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/v09/Translator.cs @@ -30,6 +30,9 @@ internal class Translator : SqlTranslator /// public override string DateTimeFormatString => @"'(TIMESTAMP '\'yyyy\-MM\-dd HH\:mm\:ss\.fff\'\)"; + /// + public override string DateOnlyFormatString => @"'(DATE '\'yyyy\-MM\-dd\'\)"; + /// public override string TimeSpanFormatString => "(INTERVAL '{0}{1} {2}:{3}:{4}.{5:000}' DAY(6) TO SECOND(3))"; diff --git a/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/v8_0/ServerInfoProvider.cs b/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/v8_0/ServerInfoProvider.cs index aaecae7730..4337440532 100644 --- a/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/v8_0/ServerInfoProvider.cs +++ b/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/v8_0/ServerInfoProvider.cs @@ -178,6 +178,11 @@ public override DataTypeCollection GetDataTypesInfo() dtc.Interval = DataTypeInfo.Range(SqlType.Interval, commonFeatures, ValueRange.TimeSpan, "interval"); +#if DO_DATEONLY + dtc.DateOnly = DataTypeInfo.Range(SqlType.Date, commonFeatures, ValueRange.DateOnly, "date"); + dtc.TimeOnly = DataTypeInfo.Range(SqlType.Time, commonFeatures, ValueRange.TimeOnly, "time"); +#endif + dtc.Char = DataTypeInfo.Stream(SqlType.Char, commonFeatures, MaxCharLength, "character", "char", "bpchar"); dtc.VarChar = DataTypeInfo.Stream(SqlType.VarChar, commonFeatures, MaxCharLength, "character varying", "varchar"); dtc.VarCharMax = DataTypeInfo.Regular(SqlType.VarCharMax, commonFeatures, "text"); diff --git a/Orm/Xtensive.Orm.PostgreSql/Xtensive.Orm.PostgreSql.csproj b/Orm/Xtensive.Orm.PostgreSql/Xtensive.Orm.PostgreSql.csproj index 47da25e64c..60f1fd7fbf 100644 --- a/Orm/Xtensive.Orm.PostgreSql/Xtensive.Orm.PostgreSql.csproj +++ b/Orm/Xtensive.Orm.PostgreSql/Xtensive.Orm.PostgreSql.csproj @@ -15,7 +15,7 @@ 2 - TRACE;DEBUG + $(DefineConstants);TRACE;DEBUG TRACE diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/Compiler.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/Compiler.cs index cfc4f60a44..5505da3655 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/Compiler.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/Compiler.cs @@ -150,6 +150,7 @@ public override void Visit(SqlAlterTable node) /// public override void Visit(SqlFunctionCall node) { + var arguments = node.Arguments; switch (node.FunctionType) { case SqlFunctionType.CharLength: (SqlDml.FunctionCall("DATALENGTH", node.Arguments) / 2).AcceptVisitor(this); @@ -199,6 +200,15 @@ public override void Visit(SqlFunctionCall node) case SqlFunctionType.DateTimeAddYears: Visit(DateAddYear(node.Arguments[0], node.Arguments[1])); return; + case SqlFunctionType.DateOnlyAddDays: + Visit(DateAddDay(arguments[0], arguments[1])); + return; + case SqlFunctionType.TimeOnlyAddHours: + Visit(DateAddHour(arguments[0], arguments[1])); + return; + case SqlFunctionType.TimeOnlyAddMinutes: + Visit(DateAddMinute(arguments[0], arguments[1])); + return; case SqlFunctionType.DateTimeTruncate: DateTimeTruncate(node.Arguments[0]).AcceptVisitor(this); return; diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/ServerInfoProvider.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/ServerInfoProvider.cs index 908ef98576..29bf200f16 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/ServerInfoProvider.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/ServerInfoProvider.cs @@ -251,9 +251,14 @@ public override DataTypeCollection GetDataTypesInfo() ValueRange.Double, "float"); types.DateTime = DataTypeInfo.Range(SqlType.DateTime, common | index, - new ValueRange(new DateTime(1753, 1, 1), new DateTime(9999, 12,31)), + new ValueRange(new DateTime(1753, 1, 1), new DateTime(9999, 12, 31)), "datetime", "smalldatetime"); +#if DO_DATEONLY + types.DateOnly = DataTypeInfo.Range(SqlType.Date, common | index,new ValueRange(new DateOnly(1, 1, 1), new DateOnly(9999, 12, 31)), "date"); + types.TimeOnly = DataTypeInfo.Range(SqlType.Time, common | index,new ValueRange(TimeOnly.MinValue, TimeOnly.MaxValue), "time"); +#endif + types.Char = DataTypeInfo.Stream(SqlType.Char, common | index, 4000, "nchar", "char"); types.VarChar = DataTypeInfo.Stream(SqlType.VarChar, common | index, 4000, "nvarchar", "varchar"); types.VarCharMax = DataTypeInfo.Regular(SqlType.VarCharMax, common, "nvarchar(max)", "ntext", "varchar(max)", "text", "xml"); diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/Translator.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/Translator.cs index cd34db9e3b..14245d7f24 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/Translator.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/Translator.cs @@ -20,6 +20,8 @@ namespace Xtensive.Sql.Drivers.SqlServer.v09 internal class Translator : SqlTranslator { public override string DateTimeFormatString => @"'cast ('\'yyyy\-MM\-ddTHH\:mm\:ss\.fff\'' as datetime)'"; + public override string DateOnlyFormatString => @"'cast ('\'yyyy\-MM\-dd\'' as date)'"; + public override string TimeOnlyFormatString => @"'cast ('\'HH\:mm\:ss\.fff\'' as time)'"; public override string TimeSpanFormatString => string.Empty; public override void Initialize() @@ -567,6 +569,13 @@ public override void Translate(SqlCompilerContext context, object literalValue) case long v: _ = output.Append($"CAST({v} as BIGINT)"); break; +#if DO_DATEONLY + case DateOnly dateOnly: + var dateOnlyRange = (ValueRange) Driver.ServerInfo.DataTypes.DateTime.ValueRange; + var newDateOnly = ValueRangeValidator.Correct(dateOnly.ToDateTime(TimeOnly.MinValue), dateOnlyRange).Date; + output.Append(newDateOnly.ToString(DateOnlyFormatString, DateTimeFormat)); + break; +#endif default: base.Translate(context, literalValue); break; diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v10/ServerInfoProvider.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v10/ServerInfoProvider.cs index 57afca22ff..e4653b4f5c 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v10/ServerInfoProvider.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v10/ServerInfoProvider.cs @@ -29,15 +29,22 @@ public override DataTypeCollection GetDataTypesInfo() var index = DataTypeFeatures.Indexing | DataTypeFeatures.Clustering | DataTypeFeatures.FillFactor | DataTypeFeatures.KeyConstraint; - types.DateTime = DataTypeInfo.Range(SqlType.DateTime, common | index, - new ValueRange(new DateTime(1, 1, 1), new DateTime(9999, 12, 31)), - "datetime2", "datetime", "date", "time", "smalldatetime"); types.DateTimeOffset = DataTypeInfo.Range(SqlType.DateTimeOffset, common | index, new ValueRange(new DateTimeOffset(1, 1, 1, 0, 0, 0, 0, new TimeSpan(0)), new DateTimeOffset(9999, 12, 31, 0, 0, 0, 0, new TimeSpan(0))), "datetimeoffset"); +#if DO_DATEONLY + types.DateTime = DataTypeInfo.Range(SqlType.DateTime, common | index, + new ValueRange(new DateTime(1, 1, 1), new DateTime(9999, 12, 31)), + "datetime2", "datetime", "smalldatetime"); +#else + types.DateTime = DataTypeInfo.Range(SqlType.DateTime, common | index, + new ValueRange(new DateTime(1, 1, 1), new DateTime(9999, 12, 31)), + "datetime2", "datetime", "date", "time", "smalldatetime"); +#endif + types.VarBinaryMax = DataTypeInfo.Regular(SqlType.VarBinaryMax, common, "varbinary(max)", "image"); var geo = DataTypeFeatures.Default | DataTypeFeatures.Nullable | DataTypeFeatures.Multiple | DataTypeFeatures.Spatial; diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v10/Translator.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v10/Translator.cs index 4cacf3b964..43bd6ee109 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v10/Translator.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v10/Translator.cs @@ -17,6 +17,9 @@ internal class Translator : v09.Translator /// public override string DateTimeFormatString => @"'cast ('\'yyyy\-MM\-ddTHH\:mm\:ss\.fffffff\'' as datetime2)'"; + /// + public override string TimeOnlyFormatString => @"'cast ('\'HH\:mm\:ss\.fffffff\'' as time)'"; + public string DateTimeOffsetFormatString => @"'cast ('\'yyyy\-MM\-dd HH\:mm\:ss\.fffffff\ zzz\'' as datetimeoffset)'"; /// diff --git a/Orm/Xtensive.Orm.Tests.Core/Xtensive.Orm.Tests.Core.csproj b/Orm/Xtensive.Orm.Tests.Core/Xtensive.Orm.Tests.Core.csproj index e8e39dd906..d5701e209f 100644 --- a/Orm/Xtensive.Orm.Tests.Core/Xtensive.Orm.Tests.Core.csproj +++ b/Orm/Xtensive.Orm.Tests.Core/Xtensive.Orm.Tests.Core.csproj @@ -11,7 +11,7 @@ 2 - TRACE;DEBUG + $(DefineConstants);TRACE;DEBUG TRACE @@ -26,5 +26,5 @@ - + \ No newline at end of file diff --git a/Orm/Xtensive.Orm.Tests.Framework/Xtensive.Orm.Tests.Framework.csproj b/Orm/Xtensive.Orm.Tests.Framework/Xtensive.Orm.Tests.Framework.csproj index 533ab671b9..255ac46913 100644 --- a/Orm/Xtensive.Orm.Tests.Framework/Xtensive.Orm.Tests.Framework.csproj +++ b/Orm/Xtensive.Orm.Tests.Framework/Xtensive.Orm.Tests.Framework.csproj @@ -2,7 +2,7 @@ true false - TRACE + $(DefineConstants);TRACE Xtensive diff --git a/Orm/Xtensive.Orm.Tests.Sql/Xtensive.Orm.Tests.Sql.csproj b/Orm/Xtensive.Orm.Tests.Sql/Xtensive.Orm.Tests.Sql.csproj index c5c0e6b7db..3c335cd592 100644 --- a/Orm/Xtensive.Orm.Tests.Sql/Xtensive.Orm.Tests.Sql.csproj +++ b/Orm/Xtensive.Orm.Tests.Sql/Xtensive.Orm.Tests.Sql.csproj @@ -11,7 +11,7 @@ 2 - TRACE;DEBUG + $(DefineConstants);TRACE;DEBUG TRACE diff --git a/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/ComparisonTest.cs b/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/ComparisonTest.cs index e0dd74a9fb..9d7406c100 100644 --- a/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/ComparisonTest.cs +++ b/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/ComparisonTest.cs @@ -1,9 +1,10 @@ -// Copyright (C) 2016-2021 Xtensive LLC. +// Copyright (C) 2016-2022 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Alex Groznov // Created: 2016.08.01 +using System; using NUnit.Framework; using Xtensive.Orm.Tests.Linq.DateTimeAndDateTimeOffset.Model; @@ -23,6 +24,10 @@ public void EqualsTest() RunWrongTest(c => c.MillisecondDateTime==WrongMillisecondDateTime); RunWrongTest(c => c.NullableDateTime==WrongDateTime); RunWrongTest(c => c.NullableDateTime==null); +#if DO_DATEONLY + RunTest(c => c.DateOnly == FirstDateOnly); + RunTest(c => c.NullableDateOnly == NullableDateOnly); +#endif }); } @@ -33,6 +38,9 @@ public void NotEqualTest() RunTest(c=>c.DateTime!=FirstDateTime.AddYears(1)); RunTest(c => c.MillisecondDateTime!=FirstMillisecondDateTime.AddYears(1)); RunTest(c=>c.NullableDateTime!=NullableDateTime.AddYears(1)); +#if DO_DATEONLY + RunTest(c => c.DateOnly != FirstDateOnly.AddYears(1)); +#endif }); } @@ -52,6 +60,9 @@ public void CompareTest() RunWrongTest(c => c.DateTime > FirstDateTime); RunWrongTest(c => c.MillisecondDateTime > FirstMillisecondDateTime); RunWrongTest(c => c.MillisecondDateTime < FirstMillisecondDateTime.Date); +#if DO_DATEONLY + RunTest(c => c.DateOnly > FirstDateOnly.AddDays(-1)); +#endif }); } diff --git a/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/DateTimeToIsoTest.cs b/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/DateTimeToIsoTest.cs index b58dd50aee..4e9139e9b7 100644 --- a/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/DateTimeToIsoTest.cs +++ b/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/DateTimeToIsoTest.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016 Xtensive LLC. +// Copyright (C) 2016 Xtensive LLC. // All rights reserved. // For conditions of distribution and use, see license. // Created by: Alex Groznov diff --git a/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/DistinctTest.cs b/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/DistinctTest.cs index e1c301044d..9e55216189 100644 --- a/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/DistinctTest.cs +++ b/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/DistinctTest.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016 Xtensive LLC. +// Copyright (C) 2016 Xtensive LLC. // All rights reserved. // For conditions of distribution and use, see license. // Created by: Alex Groznov @@ -18,6 +18,10 @@ public class DistinctTest : DateTimeBaseTest public void DistinctByDateTimeTest() { ExecuteInsideSession(() => DistinctPrivate(c => c.DateTime)); +#if DO_DATEONLY + ExecuteInsideSession(() => DistinctPrivate(c => c.DateOnly)); + ExecuteInsideSession(() => DistinctPrivate(c => c.TimeOnly)); +#endif } [Test] diff --git a/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/JoinTest.cs b/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/JoinTest.cs index 7eb9f0794d..6f1236a72e 100644 --- a/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/JoinTest.cs +++ b/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/JoinTest.cs @@ -17,6 +17,14 @@ public void DateTimeJoinTest() (left, right) => new JoinResult { LeftId = left.Id, RightId = right.Id, LeftDateTime = left.DateTime, RightDateTime = right.DateTime }, c => c.LeftId, c => c.RightId)); +#if DO_DATEONLY + ExecuteInsideSession(() => JoinPrivate, DateOnly, long>( + left => left.DateOnly, + right => right.DateOnly, + (left, right) => new JoinResult { LeftId = left.Id, RightId = right.Id, LeftDateTime = left.DateOnly, RightDateTime = right.DateOnly }, + c => c.LeftId, + c => c.RightId)); +#endif } [Test] diff --git a/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/OperationsTest.cs b/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/OperationsTest.cs index b0b2bb46d7..b1c7f2db41 100644 --- a/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/OperationsTest.cs +++ b/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/OperationsTest.cs @@ -22,6 +22,13 @@ public void AddYearsTest() RunWrongTest(c => c.DateTime.AddYears(1) == FirstDateTime.AddYears(2)); RunWrongTest(c => c.MillisecondDateTime.AddYears(-1) == FirstMillisecondDateTime.AddYears(-2)); RunWrongTest(c => c.NullableDateTime.Value.AddYears(33) == NullableDateTime.AddYears(44)); +#if DO_DATEONLY + RunTest(c => c.DateOnly.AddYears(1) == FirstDateOnly.AddYears(1)); + RunTest(c => c.NullableDateOnly.Value.AddYears(33) == NullableDateOnly.AddYears(33)); + + RunWrongTest(c => c.DateOnly.AddYears(1) == FirstDateOnly.AddYears(2)); + RunWrongTest(c => c.NullableDateOnly.Value.AddYears(33) == NullableDateOnly.AddYears(44)); +#endif }); } @@ -36,6 +43,13 @@ public void AddMonthsTest() RunWrongTest(c => c.DateTime.AddMonths(1) == FirstDateTime.AddMonths(2)); RunWrongTest(c => c.MillisecondDateTime.AddMonths(-1) == FirstMillisecondDateTime.AddMonths(-2)); RunWrongTest(c => c.NullableDateTime.Value.AddMonths(33) == NullableDateTime.AddMonths(44)); +#if DO_DATEONLY + RunTest(c => c.DateOnly.AddMonths(1) == FirstDateOnly.AddMonths(1)); + RunTest(c => c.NullableDateOnly.Value.AddMonths(33) == NullableDateOnly.AddMonths(33)); + + RunWrongTest(c => c.DateOnly.AddMonths(1) == FirstDateOnly.AddMonths(2)); + RunWrongTest(c => c.NullableDateOnly.Value.AddMonths(33) == NullableDateOnly.AddMonths(44)); +#endif }); } @@ -50,6 +64,13 @@ public void AddDaysTest() RunWrongTest(c => c.DateTime.AddDays(1) == FirstDateTime.AddDays(2)); RunWrongTest(c => c.MillisecondDateTime.AddDays(-1) == FirstMillisecondDateTime.AddDays(-2)); RunWrongTest(c => c.NullableDateTime.Value.AddDays(33) == NullableDateTime.AddDays(44)); +#if DO_DATEONLY + RunTest(c => c.DateOnly.AddDays(1) == FirstDateOnly.AddDays(1)); + RunTest(c => c.NullableDateOnly.Value.AddDays(33) == NullableDateOnly.AddDays(33)); + + RunWrongTest(c => c.DateOnly.AddDays(1) == FirstDateOnly.AddDays(2)); + RunWrongTest(c => c.NullableDateOnly.Value.AddDays(33) == NullableDateOnly.AddDays(44)); +#endif }); } @@ -78,6 +99,11 @@ public void AddMinutesTest() RunWrongTest(c => c.DateTime.AddMinutes(1) == FirstDateTime.AddMinutes(2)); RunWrongTest(c => c.MillisecondDateTime.AddMinutes(-1) == FirstMillisecondDateTime.AddMinutes(-2)); RunWrongTest(c => c.NullableDateTime.Value.AddMinutes(33) == NullableDateTime.AddMinutes(44)); +#if DO_DATEONLY + RunTest(c => c.TimeOnly.AddMinutes(1) == FirstTimeOnly.AddMinutes(1)); + + RunWrongTest(c => c.TimeOnly.AddMinutes(1) == FirstTimeOnly.AddMinutes(2)); +#endif }); } @@ -188,6 +214,11 @@ public void MinusDateTimeTest() RunWrongTest(c => c.DateTime - SecondDateTime == FirstDateTime - WrongDateTime); RunWrongTest(c => c.MillisecondDateTime - SecondDateTime == FirstMillisecondDateTime - WrongDateTime); RunWrongTest(c => c.NullableDateTime - SecondDateTime == NullableDateTime - WrongDateTime); + +#if DO_DATEONLY + RunTest(c => c.TimeOnly - SecondTimeOnly == FirstTimeOnly - SecondTimeOnly); + RunWrongTest(c => c.TimeOnly - SecondTimeOnly == FirstTimeOnly - WrongTimeOnly); +#endif }); } diff --git a/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/OrderByTest.cs b/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/OrderByTest.cs index 925a678cd6..d7fd92c34e 100644 --- a/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/OrderByTest.cs +++ b/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/OrderByTest.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016 Xtensive LLC. +// Copyright (C) 2016 Xtensive LLC. // All rights reserved. // For conditions of distribution and use, see license. // Created by: Alex Groznov @@ -20,6 +20,11 @@ public void DateTimeOrderByTest() ExecuteInsideSession(() => { OrderByPrivate(c => c.DateTime, c => c.Id); OrderByPrivate(c => c.DateTime, c => c); +#if DO_DATEONLY + OrderByPrivate(c => c.DateOnly, c => c.Id); + OrderByPrivate(c => c.DateOnly, c => c); + OrderByPrivate(c => c.TimeOnly, c => c.Id ); +#endif }); } diff --git a/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/PartsExtractionTest.cs b/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/PartsExtractionTest.cs index fb5e5c8585..6f990d55e1 100644 --- a/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/PartsExtractionTest.cs +++ b/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/PartsExtractionTest.cs @@ -37,6 +37,13 @@ public void ExtractMonthTest() RunWrongTest(c => c.DateTime.Month == WrongDateTime.Month); RunWrongTest(c => c.MillisecondDateTime.Month == WrongMillisecondDateTime.Month); RunWrongTest(c => c.NullableDateTime.Value.Month == WrongDateTime.Month); +#if DO_DATEONLY + RunTest(c => c.DateOnly.Month == FirstDateOnly.Month); + RunTest(c => c.NullableDateOnly.Value.Month == NullableDateOnly.Month); + + RunWrongTest(c => c.DateOnly.Month == WrongDateOnly.Month); + RunWrongTest(c => c.NullableDateOnly.Value.Month == WrongDateOnly.Month); +#endif }); } @@ -93,6 +100,11 @@ public void ExtractSecondTest() RunWrongTest(c => c.DateTime.Second == WrongDateTime.Second); RunWrongTest(c => c.MillisecondDateTime.Second == WrongMillisecondDateTime.Second); RunWrongTest(c => c.NullableDateTime.Value.Second == WrongDateTime.Second); +#if DO_DATEONLY + RunTest(c => c.TimeOnly.Second == FirstTimeOnly.Second); + + RunWrongTest(c => c.TimeOnly.Second == WrongTimeOnly.Second); +#endif }); } diff --git a/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/WhereTest.cs b/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/WhereTest.cs index 56dec921c9..ac616be831 100644 --- a/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/WhereTest.cs +++ b/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTime/WhereTest.cs @@ -21,6 +21,13 @@ public void DateTimeWhereTest() WherePrivate(c => c.DateTime == FirstDateTime, c => c.Id); WherePrivate(c => c.DateTime.Hour == FirstDateTime.Hour, c => c.Id); WherePrivate(c => c.DateTime.Second == FirstDateTime.Second, c => c.Id); + +#if DO_DATEONLY + WherePrivate(c => c.DateOnly == FirstDateOnly, c => c.Id); + WherePrivate(c => c.TimeOnly == FirstTimeOnly, c => c.Id); + WherePrivate(c => c.TimeOnly.Hour == FirstTimeOnly.Hour, c => c.Id); + WherePrivate(c => c.TimeOnly.Second == FirstTimeOnly.Second, c => c.Id); +#endif }); } diff --git a/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTimeBaseTest.cs b/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTimeBaseTest.cs index 91fa766b84..4339392a3d 100644 --- a/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTimeBaseTest.cs +++ b/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/DateTimeBaseTest.cs @@ -25,6 +25,16 @@ public abstract class DateTimeBaseTest : BaseTest protected static readonly DateTime SecondMillisecondDateTime = SecondDateTime.AddMilliseconds(987); protected static readonly DateTime WrongMillisecondDateTime = WrongDateTime.AddMilliseconds(654); +#if DO_DATEONLY + protected static readonly DateOnly FirstDateOnly = DateOnly.FromDateTime(FirstDateTime); + protected static readonly DateOnly NullableDateOnly = DateOnly.FromDateTime(SecondDateTime); + protected static readonly DateOnly WrongDateOnly = DateOnly.FromDateTime(WrongDateTime); + + protected static readonly TimeOnly FirstTimeOnly = TimeOnly.FromDateTime(FirstDateTime); + protected static readonly TimeOnly SecondTimeOnly = TimeOnly.FromDateTime(SecondDateTime); + protected static readonly TimeOnly WrongTimeOnly = TimeOnly.FromDateTime(WrongDateTime); +#endif + protected override void RegisterTypes(DomainConfiguration configuration) { configuration.Types.Register(typeof (SingleDateTimeEntity)); @@ -38,31 +48,36 @@ protected override void PopulateEntities(Session session) new SingleDateTimeEntity { DateTime = FirstDateTime, MillisecondDateTime = FirstMillisecondDateTime, +#if DO_DATEONLY + DateOnly = DateOnly.FromDateTime(FirstDateTime), + NullableDateOnly = DateOnly.FromDateTime(NullableDateTime), + TimeOnly = FirstTimeOnly, +#endif NullableDateTime = NullableDateTime }; - new DateTimeEntity { DateTime = FirstDateTime }; - new DateTimeEntity { DateTime = FirstDateTime }; - new DateTimeEntity { DateTime = FirstDateTime.Date }; - new DateTimeEntity { DateTime = SecondDateTime }; - new DateTimeEntity { DateTime = SecondDateTime.Date }; - new DateTimeEntity { DateTime = new DateTime(FirstDateTime.Year, FirstDateTime.Month, FirstDateTime.Day, FirstDateTime.Hour, FirstDateTime.Minute, 0) }; - new DateTimeEntity { DateTime = new DateTime(FirstDateTime.Ticks, DateTimeKind.Local) }; - new DateTimeEntity { DateTime = FirstDateTime.Add(new TimeSpan(987, 23, 34, 45)) }; - new DateTimeEntity { DateTime = FirstDateTime.AddYears(1) }; - new DateTimeEntity { DateTime = FirstDateTime.AddYears(-2) }; - new DateTimeEntity { DateTime = FirstDateTime.AddMonths(44) }; - new DateTimeEntity { DateTime = FirstDateTime.AddMonths(-55) }; - new DateTimeEntity { DateTime = SecondDateTime.AddHours(5) }; - new DateTimeEntity { DateTime = SecondDateTime.AddHours(-15) }; - new DateTimeEntity { DateTime = SecondDateTime.AddMinutes(59) }; - new DateTimeEntity { DateTime = SecondDateTime.AddMinutes(-49) }; - new DateTimeEntity { DateTime = SecondDateTime.AddSeconds(57) }; - new DateTimeEntity { DateTime = SecondDateTime.AddSeconds(-5) }; + new DateTimeEntity(FirstDateTime); + new DateTimeEntity(FirstDateTime); + new DateTimeEntity(FirstDateTime.Date); + new DateTimeEntity(SecondDateTime); + new DateTimeEntity(SecondDateTime.Date); + new DateTimeEntity(new DateTime(FirstDateTime.Year, FirstDateTime.Month, FirstDateTime.Day, FirstDateTime.Hour, FirstDateTime.Minute, 0)); + new DateTimeEntity(new DateTime(FirstDateTime.Ticks, DateTimeKind.Local)); + new DateTimeEntity(FirstDateTime.Add(new TimeSpan(987, 23, 34, 45))); + new DateTimeEntity(FirstDateTime.AddYears(1)); + new DateTimeEntity(FirstDateTime.AddYears(-2)); + new DateTimeEntity(FirstDateTime.AddMonths(44)); + new DateTimeEntity(FirstDateTime.AddMonths(-55)); + new DateTimeEntity(SecondDateTime.AddHours(5)); + new DateTimeEntity(SecondDateTime.AddHours(-15)); + new DateTimeEntity(SecondDateTime.AddMinutes(59)); + new DateTimeEntity(SecondDateTime.AddMinutes(-49)); + new DateTimeEntity(SecondDateTime.AddSeconds(57)); + new DateTimeEntity(SecondDateTime.AddSeconds(-5)); var dateTime = FirstDateTime.AddYears(10); for (var i = 0; i < 60; ++i) - new DateTimeEntity { DateTime = dateTime.AddSeconds(i) }; + new DateTimeEntity(dateTime.AddSeconds(i)); new MillisecondDateTimeEntity { DateTime = FirstMillisecondDateTime }; new MillisecondDateTimeEntity { DateTime = FirstMillisecondDateTime }; diff --git a/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/Model.cs b/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/Model.cs index e183016ded..97ae038ac3 100644 --- a/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/Model.cs +++ b/Orm/Xtensive.Orm.Tests/Linq/DateTimeAndDateTimeOffset/Model.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016 Xtensive LLC. +// Copyright (C) 2016 Xtensive LLC. // All rights reserved. // For conditions of distribution and use, see license. // Created by: Alex Groznov @@ -22,6 +22,17 @@ public class SingleDateTimeEntity : Entity [Field] public DateTime? NullableDateTime { get; set; } + +#if DO_DATEONLY + [Field] + public DateOnly DateOnly { get; set; } + + [Field] + public DateOnly? NullableDateOnly { get; set; } + + [Field] + public TimeOnly TimeOnly { get; set; } +#endif } [HierarchyRoot] @@ -48,6 +59,23 @@ public class DateTimeEntity : Entity [Field] public DateTime DateTime { get; set; } + +#if DO_DATEONLY + [Field] + public DateOnly DateOnly { get; set; } + + [Field] + public TimeOnly TimeOnly { get; set; } +#endif + + public DateTimeEntity(DateTime dateTime) + { + DateTime = dateTime; +#if DO_DATEONLY + DateOnly = DateOnly.FromDateTime(dateTime); + TimeOnly = TimeOnly.FromDateTime(dateTime); +#endif + } } [HierarchyRoot] diff --git a/Orm/Xtensive.Orm.Tests/Storage/SchemaSharing/EntityManipulation/Model.cs b/Orm/Xtensive.Orm.Tests/Storage/SchemaSharing/EntityManipulation/Model.cs index 770455d796..90f0867bb3 100644 --- a/Orm/Xtensive.Orm.Tests/Storage/SchemaSharing/EntityManipulation/Model.cs +++ b/Orm/Xtensive.Orm.Tests/Storage/SchemaSharing/EntityManipulation/Model.cs @@ -4,6 +4,8 @@ // Created by: Alexey Kulakov // Created: 2017.04.05 +using System; + namespace Xtensive.Orm.Tests.Storage.SchemaSharing.EntityManipulation.Model { namespace Part1 @@ -17,6 +19,14 @@ public class TestEntity1 : Entity [Field] public string Text { get; set; } +#if DO_DATEONLY + [Field] + public DateOnly DateOnly { get; set; } + + [Field] + public TimeOnly TimeOnly { get; set; } +#endif + [Field] public string DatabaseName { get; set; } diff --git a/Orm/Xtensive.Orm.Tests/Storage/SchemaSharing/EntityManipulation/SimpleEntityManipulationTest.cs b/Orm/Xtensive.Orm.Tests/Storage/SchemaSharing/EntityManipulation/SimpleEntityManipulationTest.cs index e9bf5dd3e2..80fa8d59ab 100644 --- a/Orm/Xtensive.Orm.Tests/Storage/SchemaSharing/EntityManipulation/SimpleEntityManipulationTest.cs +++ b/Orm/Xtensive.Orm.Tests/Storage/SchemaSharing/EntityManipulation/SimpleEntityManipulationTest.cs @@ -405,11 +405,23 @@ private void Update(Session session, Key[] createdKeys, int initialCountOfEntiti Assert.That(a.DatabaseName, Is.EqualTo(databaseAndSchema.First)); Assert.That(a.SchemaName, Is.EqualTo(databaseAndSchema.Second)); + var now = DateTime.UtcNow; + a.Text = updatedText; +#if DO_DATEONLY + var dateOnly = DateOnly.FromDateTime(now); + var timeOnly = TimeOnly.FromDateTime(now); + a.DateOnly = dateOnly; + a.TimeOnly = timeOnly; +#endif session.SaveChanges(); Assert.That(session.Query.All().Count(), Is.EqualTo(initialCountOfEntities + 1)); Assert.That(session.Query.All().FirstOrDefault(e => e.Text == updatedText), Is.Not.Null); +#if DO_DATEONLY + Assert.AreEqual(session.Query.All().FirstOrDefault(e => e.Text == updatedText).DateOnly, dateOnly); + Assert.AreEqual(session.Query.All().FirstOrDefault(e => e.Text == updatedText).TimeOnly, timeOnly); +#endif Assert.That(session.Query.All().FirstOrDefault(e => e.Text == text), Is.Null); Assert.That( session.Query.All() diff --git a/Orm/Xtensive.Orm.Tests/Storage/SetFieldTest.cs b/Orm/Xtensive.Orm.Tests/Storage/SetFieldTest.cs index bb67b45686..0a33ea6034 100644 --- a/Orm/Xtensive.Orm.Tests/Storage/SetFieldTest.cs +++ b/Orm/Xtensive.Orm.Tests/Storage/SetFieldTest.cs @@ -25,6 +25,11 @@ public class Book : Entity [Field] public DateTime Date { get; set; } +#if DO_DATEONLY + [Field] + public DateOnly DateOnly { get; set; } +#endif + [Field] public Direction? NullableDirection { get; set; } @@ -61,6 +66,11 @@ public void CombinedTest() AssertIsNotCalled(() => { book.Title = "A"; }); AssertIsCalled (() => { book.Date = new DateTime(1,2,3); }); AssertIsNotCalled(() => { book.Date = new DateTime(1,2,3); }); + +#if DO_DATEONLY + AssertIsCalled (() => { book.DateOnly = new DateOnly(1,2,3); }); + AssertIsNotCalled(() => { book.DateOnly = new DateOnly(1,2,3); }); +#endif var image = new byte[] {1, 2, 3}; AssertIsCalled (() => { book.Image = image; }); diff --git a/Orm/Xtensive.Orm/Linq/ExpressionWriter.cs b/Orm/Xtensive.Orm/Linq/ExpressionWriter.cs index 55dd8b66f4..42668d4314 100644 --- a/Orm/Xtensive.Orm/Linq/ExpressionWriter.cs +++ b/Orm/Xtensive.Orm/Linq/ExpressionWriter.cs @@ -361,6 +361,18 @@ protected override Expression VisitConstant(ConstantExpression c) Write(c.Value.ToString()); Write("\")"); } +#if DO_DATEONLY + else if (type == WellKnownTypes.DateOnly) { + Write("DateOnly.Parse(\""); + Write(c.Value.ToString()); + Write("\")"); + } + else if (type == WellKnownTypes.TimeOnly) { + Write("TimeOnly.Parse(\""); + Write(c.Value.ToString()); + Write("\")"); + } +#endif else if (c.Value is Type typeValue) { Write("typeof("); Write(GetTypeName(typeValue)); diff --git a/Orm/Xtensive.Orm/Orm/Linq/ExpressionExtensions.cs b/Orm/Xtensive.Orm/Orm/Linq/ExpressionExtensions.cs index 9da5e7637d..99ff1e1e3d 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/ExpressionExtensions.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/ExpressionExtensions.cs @@ -45,9 +45,12 @@ public static bool IsAnonymousConstructor(this Expression expression) public static bool IsNewExpressionSupportedByStorage(this Expression expression) => expression.NodeType == ExpressionType.New - && (expression.Type == WellKnownTypes.TimeSpan - || expression.Type == WellKnownTypes.DateTime - || expression.Type == WellKnownTypes.DateTimeOffset); + && expression.Type switch { var t => + t == WellKnownTypes.TimeSpan || t == WellKnownTypes.DateTime || t == WellKnownTypes.DateTimeOffset +#if DO_DATEONLY + || t == WellKnownTypes.DateOnly || t == WellKnownTypes.TimeOnly +#endif + }; public static bool IsQuery(this Expression expression) => expression.Type.IsOfGenericInterface(WellKnownInterfaces.QueryableOfT); diff --git a/Orm/Xtensive.Orm/Orm/Linq/ItemToTupleConverter{TItem}.cs b/Orm/Xtensive.Orm/Orm/Linq/ItemToTupleConverter{TItem}.cs index cbed9e56ea..775a064917 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/ItemToTupleConverter{TItem}.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/ItemToTupleConverter{TItem}.cs @@ -97,13 +97,16 @@ private static bool TypeIsStorageMappable(Type type) type = type.StripNullable(); return type.IsPrimitive || type.IsEnum || - type==WellKnownTypes.ByteArray || - type==WellKnownTypes.Decimal || - type==WellKnownTypes.String || - type==WellKnownTypes.DateTime || - type==WellKnownTypes.DateTimeOffset || - type==WellKnownTypes.Guid || - type==WellKnownTypes.TimeSpan; + type == WellKnownTypes.ByteArray || + type == WellKnownTypes.Decimal || + type == WellKnownTypes.String || + type == WellKnownTypes.DateTime || + type == WellKnownTypes.DateTimeOffset || +#if DO_DATEONLY + type == WellKnownTypes.DateOnly || type == WellKnownTypes.TimeOnly || +#endif + type == WellKnownTypes.Guid || + type == WellKnownTypes.TimeSpan; } diff --git a/Orm/Xtensive.Orm/Orm/Linq/MemberCompilation/MemberCompilerProvider.cs b/Orm/Xtensive.Orm/Orm/Linq/MemberCompilation/MemberCompilerProvider.cs index 275cec41da..aa1a586aa6 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/MemberCompilation/MemberCompilerProvider.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/MemberCompilation/MemberCompilerProvider.cs @@ -50,9 +50,7 @@ public Delegate GetUntypedCompiler(MemberInfo target) { ArgumentValidator.EnsureArgumentNotNull(target, nameof(target)); - return compilers.TryGetValue(GetCompilerKey(target), out var compiler) - ? compiler - : null; + return compilers.GetValueOrDefault(GetCompilerKey(target)); } public Func GetCompiler(MemberInfo target) @@ -103,14 +101,15 @@ private void UpdateRegistry( { foreach (var (targetMember, compiler) in newRegistrations) { var key = GetCompilerKey(targetMember); - if (conflictHandlingMethod != ConflictHandlingMethod.Overwrite && compilers.ContainsKey(key)) { - if (conflictHandlingMethod == ConflictHandlingMethod.ReportError) { - throw new InvalidOperationException(string.Format( - Strings.ExCompilerForXIsAlreadyRegistered, targetMember.GetFullName(true))); + if (!compilers.TryAdd(key, compiler)) { + switch (conflictHandlingMethod) { + case ConflictHandlingMethod.Overwrite: + compilers[key] = compiler; + break; + case ConflictHandlingMethod.ReportError: + throw new InvalidOperationException(string.Format(Strings.ExCompilerForXIsAlreadyRegistered, targetMember.GetFullName(true))); } - continue; } - compilers[key] = compiler; } } @@ -304,8 +303,7 @@ private static void ValidateCompilerParameter(ParameterInfo parameter, Type requ private static CompilerKey GetCompilerKey(MemberInfo member) { var canonicalMember = member; - var sourceProperty = canonicalMember as PropertyInfo; - if (sourceProperty!=null) { + if (canonicalMember is PropertyInfo sourceProperty) { canonicalMember = sourceProperty.GetGetMethod(); // GetGetMethod returns null in case of non public getter. if (canonicalMember==null) { diff --git a/Orm/Xtensive.Orm/Orm/Providers/Expressions/ExpressionProcessor.Helpers.cs b/Orm/Xtensive.Orm/Orm/Providers/Expressions/ExpressionProcessor.Helpers.cs index 3bb91be105..2f77209b25 100644 --- a/Orm/Xtensive.Orm/Orm/Providers/Expressions/ExpressionProcessor.Helpers.cs +++ b/Orm/Xtensive.Orm/Orm/Providers/Expressions/ExpressionProcessor.Helpers.cs @@ -194,9 +194,8 @@ private static SqlExpression OracleBlobCompare(SqlExpression left, SqlExpression private SqlExpression CompileMember(MemberInfo member, SqlExpression instance, params SqlExpression[] arguments) { - var memberCompiler = memberCompilerProvider.GetCompiler(member); - if (memberCompiler==null) - throw new NotSupportedException(string.Format(Strings.ExMemberXIsNotSupported, member.GetFullName(true))); + var memberCompiler = memberCompilerProvider.GetCompiler(member) + ?? throw new NotSupportedException(string.Format(Strings.ExMemberXIsNotSupported, member.GetFullName(true))); return memberCompiler.Invoke(instance, arguments); } diff --git a/Orm/Xtensive.Orm/Orm/Providers/Expressions/ExpressionTranslationHelpers.cs b/Orm/Xtensive.Orm/Orm/Providers/Expressions/ExpressionTranslationHelpers.cs index 400c48abbd..5cfbbbec05 100644 --- a/Orm/Xtensive.Orm/Orm/Providers/Expressions/ExpressionTranslationHelpers.cs +++ b/Orm/Xtensive.Orm/Orm/Providers/Expressions/ExpressionTranslationHelpers.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2020 Xtensive LLC. +// Copyright (C) 2009-2022 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Denis Krjuchkov @@ -13,80 +13,58 @@ namespace Xtensive.Orm.Providers { internal static class ExpressionTranslationHelpers { - public static SqlExpression ToBool(SqlExpression target) - { - return Cast(target, WellKnownTypes.Bool); - } + public static SqlExpression ToBool(SqlExpression target) => + Cast(target, WellKnownTypes.Bool); - public static SqlExpression ToInt(SqlExpression target) - { - return Cast(target, WellKnownTypes.Int32); - } + public static SqlExpression ToInt(SqlExpression target) => + Cast(target, WellKnownTypes.Int32); - public static SqlExpression ToDouble(SqlExpression target) - { - return Cast(target, WellKnownTypes.Double); - } + public static SqlExpression ToDouble(SqlExpression target) => + Cast(target, WellKnownTypes.Double); - public static SqlExpression ToLong(SqlExpression target) - { - return Cast(target, WellKnownTypes.Int64); - } + public static SqlExpression ToLong(SqlExpression target) => + Cast(target, WellKnownTypes.Int64); - public static SqlExpression ToSbyte(SqlExpression target) - { - return Cast(target, WellKnownTypes.SByte); - } + public static SqlExpression ToSbyte(SqlExpression target) => + Cast(target, WellKnownTypes.SByte); - public static SqlExpression ToShort(SqlExpression target) - { - return Cast(target, WellKnownTypes.Int16); - } + public static SqlExpression ToShort(SqlExpression target) => + Cast(target, WellKnownTypes.Int16); - public static SqlExpression ToFloat(SqlExpression target) - { - return Cast(target, WellKnownTypes.Single); - } + public static SqlExpression ToFloat(SqlExpression target) => + Cast(target, WellKnownTypes.Single); - public static SqlExpression ToDecimal(SqlExpression target) - { - return Cast(target, WellKnownTypes.Decimal); - } + public static SqlExpression ToDecimal(SqlExpression target) => + Cast(target, WellKnownTypes.Decimal); - public static SqlExpression ToByte(SqlExpression target) - { - return Cast(target, WellKnownTypes.Byte); - } + public static SqlExpression ToByte(SqlExpression target) => + Cast(target, WellKnownTypes.Byte); - public static SqlExpression ToChar(SqlExpression target) - { - return Cast(target, WellKnownTypes.String); - } + public static SqlExpression ToChar(SqlExpression target) => + Cast(target, WellKnownTypes.String); - public static SqlExpression ToDateTime(SqlExpression target) - { - return Cast(target, WellKnownTypes.DateTime); - } + public static SqlExpression ToDateTime(SqlExpression target) => + Cast(target, WellKnownTypes.DateTime); - public static SqlExpression ToUint(SqlExpression target) - { - return Cast(target, WellKnownTypes.UInt32); - } +#if DO_DATEONLY + public static SqlExpression ToDate(SqlExpression target) => + Cast(target, WellKnownTypes.DateOnly); - public static SqlExpression ToUlong(SqlExpression target) - { - return Cast(target, WellKnownTypes.UInt64); - } + public static SqlExpression ToTime(SqlExpression target) => + Cast(target, WellKnownTypes.TimeOnly); +#endif - public static SqlExpression ToUshort(SqlExpression target) - { - return Cast(target, WellKnownTypes.UInt16); - } + public static SqlExpression ToUint(SqlExpression target) => + Cast(target, WellKnownTypes.UInt32); - public static SqlExpression ToString(SqlExpression target) - { - return Cast(target, WellKnownTypes.String); - } + public static SqlExpression ToUlong(SqlExpression target) => + Cast(target, WellKnownTypes.UInt64); + + public static SqlExpression ToUshort(SqlExpression target) => + Cast(target, WellKnownTypes.UInt16); + + public static SqlExpression ToString(SqlExpression target) => + Cast(target, WellKnownTypes.String); private static SqlExpression Cast(SqlExpression target, Type type) { @@ -94,4 +72,4 @@ private static SqlExpression Cast(SqlExpression target, Type type) return SqlDml.Cast(target, destinationType); } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Orm/Providers/Expressions/MemberCompilers/DateTimeCompilers.cs b/Orm/Xtensive.Orm/Orm/Providers/Expressions/MemberCompilers/DateTimeCompilers.cs index df617de4e7..2028f1c16a 100644 --- a/Orm/Xtensive.Orm/Orm/Providers/Expressions/MemberCompilers/DateTimeCompilers.cs +++ b/Orm/Xtensive.Orm/Orm/Providers/Expressions/MemberCompilers/DateTimeCompilers.cs @@ -1,6 +1,6 @@ -// Copyright (C) 2003-2010 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. +// Copyright (C) 2003-2022 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. // Created by: Denis Krjuchkov // Created: 2009.02.14 @@ -18,58 +18,40 @@ internal static class DateTimeCompilers #region Extractors [Compiler(typeof(DateTime), "Year", TargetKind.PropertyGet)] - public static SqlExpression DateTimeYear(SqlExpression _this) - { - return ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Year, _this)); - } + public static SqlExpression DateTimeYear(SqlExpression _this) => + ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Year, _this)); [Compiler(typeof(DateTime), "Month", TargetKind.PropertyGet)] - public static SqlExpression DateTimeMonth(SqlExpression _this) - { - return ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Month, _this)); - } + public static SqlExpression DateTimeMonth(SqlExpression _this) => + ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Month, _this)); [Compiler(typeof(DateTime), "Day", TargetKind.PropertyGet)] - public static SqlExpression DateTimeDay(SqlExpression _this) - { - return ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Day, _this)); - } + public static SqlExpression DateTimeDay(SqlExpression _this) => + ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Day, _this)); [Compiler(typeof(DateTime), "Hour", TargetKind.PropertyGet)] - public static SqlExpression DateTimeHour(SqlExpression _this) - { - return ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Hour, _this)); - } + public static SqlExpression DateTimeHour(SqlExpression _this) => + ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Hour, _this)); [Compiler(typeof(DateTime), "Minute", TargetKind.PropertyGet)] - public static SqlExpression DateTimeMinute(SqlExpression _this) - { - return ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Minute, _this)); - } + public static SqlExpression DateTimeMinute(SqlExpression _this) => + ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Minute, _this)); [Compiler(typeof(DateTime), "Second", TargetKind.PropertyGet)] - public static SqlExpression DateTimeSecond(SqlExpression _this) - { - return ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Second, _this)); - } + public static SqlExpression DateTimeSecond(SqlExpression _this) => + ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Second, _this)); [Compiler(typeof(DateTime), "Millisecond", TargetKind.PropertyGet)] - public static SqlExpression DateTimeMillisecond(SqlExpression _this) - { - return ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Millisecond, _this)); - } + public static SqlExpression DateTimeMillisecond(SqlExpression _this) => + ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Millisecond, _this)); [Compiler(typeof(DateTime), "TimeOfDay", TargetKind.PropertyGet)] - public static SqlExpression DateTimeTimeOfDay(SqlExpression _this) - { - return SqlDml.DateTimeMinusDateTime(_this, SqlDml.DateTimeTruncate(_this)); - } + public static SqlExpression DateTimeTimeOfDay(SqlExpression _this) => + SqlDml.DateTimeMinusDateTime(_this, SqlDml.DateTimeTruncate(_this)); [Compiler(typeof(DateTime), "Date", TargetKind.PropertyGet)] - public static SqlExpression DateTimeDate(SqlExpression _this) - { - return SqlDml.DateTimeTruncate(_this); - } + public static SqlExpression DateTimeDate(SqlExpression _this) => + SqlDml.DateTimeTruncate(_this); [Compiler(typeof(DateTime), "DayOfWeek", TargetKind.PropertyGet)] public static SqlExpression DateTimeDayOfWeek(SqlExpression _this) @@ -91,6 +73,36 @@ public static SqlExpression DateTimeDayOfYear(SqlExpression _this) return ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.DayOfYear, _this)); } +#if DO_DATEONLY + [Compiler(typeof(DateOnly), "Year", TargetKind.PropertyGet)] + public static SqlExpression DateOnlyYear(SqlExpression _this) => + ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Year, _this)); + + [Compiler(typeof(DateOnly), "Month", TargetKind.PropertyGet)] + public static SqlExpression DateOnlyMonth(SqlExpression _this) => + ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Month, _this)); + + [Compiler(typeof(DateOnly), "Day", TargetKind.PropertyGet)] + public static SqlExpression DateOnlyDay(SqlExpression _this) => + ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Day, _this)); + + [Compiler(typeof(TimeOnly), "Hour", TargetKind.PropertyGet)] + public static SqlExpression TimeOnlyHour(SqlExpression _this) => + ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Hour, _this)); + + [Compiler(typeof(TimeOnly), "Minute", TargetKind.PropertyGet)] + public static SqlExpression TimeOnlyMinute(SqlExpression _this) => + ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Minute, _this)); + + [Compiler(typeof(TimeOnly), "Second", TargetKind.PropertyGet)] + public static SqlExpression TimeOnlySecond(SqlExpression _this) => + ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Second, _this)); + + [Compiler(typeof(TimeOnly), "Millisecond", TargetKind.PropertyGet)] + public static SqlExpression TimeOnlyMillisecond(SqlExpression _this) => + ExpressionTranslationHelpers.ToInt(SqlDml.Extract(SqlDateTimePart.Millisecond, _this)); +#endif // DO_DATEONLY + #endregion #region Constructors @@ -112,7 +124,7 @@ private static SqlExpression DateTimeConstruct( [Compiler(typeof(DateTime), null, TargetKind.Constructor)] public static SqlExpression DateTimeCtor( [Type(typeof(int))] SqlExpression year, - [Type(typeof(int))] SqlExpression month, + [Type(typeof(int))] SqlExpression month, [Type(typeof(int))] SqlExpression day) { return SqlDml.DateTimeConstruct(year, month, day); @@ -143,6 +155,32 @@ public static SqlExpression DateTimeCtor( return DateTimeConstruct(year, month, day, hour, minute, second, millisecond); } +#if DO_DATEONLY + [Compiler(typeof(DateOnly), null, TargetKind.Constructor)] + public static SqlExpression DateOnlyCtor( + [Type(typeof(int))] SqlExpression year, + [Type(typeof(int))] SqlExpression month, + [Type(typeof(int))] SqlExpression day) => + SqlDml.DateOnlyConstruct(year, month, day); + + [Compiler(typeof(TimeOnly), null, TargetKind.Constructor)] + public static SqlExpression TimeOnlyCtor( + [Type(typeof(int))] SqlExpression hour, + [Type(typeof(int))] SqlExpression minute, + [Type(typeof(int))] SqlExpression second) => + SqlDml.TimeOnlyConstruct(hour, minute, second, 0); + + [Compiler(typeof(TimeOnly), null, TargetKind.Constructor)] + public static SqlExpression TimeOnlyCtor( + [Type(typeof(int))] SqlExpression hour, + [Type(typeof(int))] SqlExpression minute) => + SqlDml.TimeOnlyConstruct(hour, minute, 0, 0); + + [Compiler(typeof(TimeOnly), null, TargetKind.Constructor)] + public static SqlExpression TimeOnlyCtor([Type(typeof(long))] SqlExpression ticks) => + new SqlFunctionCall(SqlFunctionType.TimeOnlyConstruct, ticks); +#endif // DO_DATEONLY + #endregion #region Operators @@ -220,95 +258,158 @@ public static SqlExpression DateTimeOperatorSubtractionDateTime( return SqlDml.DateTimeMinusDateTime(d1, d2); } - #endregion - - [Compiler(typeof(DateTime), "Add")] - public static SqlExpression DateTimeAdd(SqlExpression _this, - [Type(typeof(TimeSpan))] SqlExpression value) +#if DO_DATEONLY + [Compiler(typeof(DateOnly), Operator.Equality, TargetKind.Operator)] + public static SqlExpression DateOnlyOperatorEquality( + [Type(typeof(DateOnly))] SqlExpression d1, + [Type(typeof(DateOnly))] SqlExpression d2) { - return SqlDml.DateTimePlusInterval(_this, value); + return d1 == d2; } - [Compiler(typeof(DateTime), "AddYears")] - public static SqlExpression DateTimeAddYears(SqlExpression _this, - [Type(typeof(int))] SqlExpression value) + [Compiler(typeof(DateOnly), Operator.Inequality, TargetKind.Operator)] + public static SqlExpression DateOnlyOperatorInequality( + [Type(typeof(DateOnly))] SqlExpression d1, + [Type(typeof(DateOnly))] SqlExpression d2) { - return SqlDml.DateTimeAddYears(_this, value); + return d1 != d2; } - [Compiler(typeof(DateTime), "AddMonths")] - public static SqlExpression DateTimeAddMonths(SqlExpression _this, - [Type(typeof(int))] SqlExpression value) + [Compiler(typeof(DateOnly), Operator.GreaterThan, TargetKind.Operator)] + public static SqlExpression DateOnlyOperatorGreaterThan( + [Type(typeof(DateOnly))] SqlExpression d1, + [Type(typeof(DateOnly))] SqlExpression d2) { - return SqlDml.DateTimeAddMonths(_this, value); + return d1 > d2; } - [Compiler(typeof(DateTime), "AddDays")] - public static SqlExpression DateTimeAddDays(SqlExpression _this, - [Type(typeof(double))] SqlExpression value) + [Compiler(typeof(DateOnly), Operator.GreaterThanOrEqual, TargetKind.Operator)] + public static SqlExpression DateOnlyOperatorGreaterThanOrEqual( + [Type(typeof(DateOnly))] SqlExpression d1, + [Type(typeof(DateOnly))] SqlExpression d2) { - return SqlDml.DateTimePlusInterval(_this, TimeSpanCompilers.TimeSpanFromDays(value)); + return d1 >= d2; } - [Compiler(typeof(DateTime), "AddHours")] - public static SqlExpression DateTimeAddHours(SqlExpression _this, - [Type(typeof(double))] SqlExpression value) + [Compiler(typeof(DateOnly), Operator.LessThan, TargetKind.Operator)] + public static SqlExpression DateOnlyOperatorLessThan( + [Type(typeof(DateOnly))] SqlExpression d1, + [Type(typeof(DateOnly))] SqlExpression d2) { - return SqlDml.DateTimePlusInterval(_this, TimeSpanCompilers.TimeSpanFromHours(value)); + return d1 < d2; } - [Compiler(typeof(DateTime), "AddMinutes")] - public static SqlExpression DateTimeAddMinutes(SqlExpression _this, - [Type(typeof(double))] SqlExpression value) + [Compiler(typeof(DateOnly), Operator.LessThanOrEqual, TargetKind.Operator)] + public static SqlExpression DateOnlyOperatorLessThanOrEqual( + [Type(typeof(DateOnly))] SqlExpression d1, + [Type(typeof(DateOnly))] SqlExpression d2) { - return SqlDml.DateTimePlusInterval(_this, TimeSpanCompilers.TimeSpanFromMinutes(value)); + return d1 <= d2; } - [Compiler(typeof(DateTime), "AddSeconds")] - public static SqlExpression DateTimeAddSeconds(SqlExpression _this, - [Type(typeof(double))] SqlExpression value) + [Compiler(typeof(TimeOnly), Operator.Equality, TargetKind.Operator)] + public static SqlExpression TimeOnlyOperatorEquality( + [Type(typeof(TimeOnly))] SqlExpression d1, + [Type(typeof(TimeOnly))] SqlExpression d2) { - return SqlDml.DateTimePlusInterval(_this, TimeSpanCompilers.TimeSpanFromSeconds(value)); + return d1 == d2; } - [Compiler(typeof(DateTime), "AddMilliseconds")] - public static SqlExpression DateTimeAddMilliseconds(SqlExpression _this, - [Type(typeof(double))] SqlExpression value) + [Compiler(typeof(TimeOnly), Operator.Inequality, TargetKind.Operator)] + public static SqlExpression TimeOnlyOperatorInequality( + [Type(typeof(TimeOnly))] SqlExpression d1, + [Type(typeof(TimeOnly))] SqlExpression d2) { - return SqlDml.DateTimePlusInterval(_this, TimeSpanCompilers.TimeSpanFromMilliseconds(value)); + return d1 != d2; } - [Compiler(typeof(DateTime), "Subtract")] - public static SqlExpression DateTimeSubtractTimeSpan(SqlExpression _this, - [Type(typeof(TimeSpan))] SqlExpression value) + [Compiler(typeof(TimeOnly), Operator.GreaterThan, TargetKind.Operator)] + public static SqlExpression TimeOnlyyOperatorGreaterThan( + [Type(typeof(TimeOnly))] SqlExpression d1, + [Type(typeof(TimeOnly))] SqlExpression d2) { - return SqlDml.DateTimeMinusInterval(_this, value); + return d1 > d2; } - [Compiler(typeof(DateTime), "Subtract")] - public static SqlExpression DateTimeSubtractDateTime(SqlExpression _this, - [Type(typeof(DateTime))] SqlExpression value) + [Compiler(typeof(TimeOnly), Operator.GreaterThanOrEqual, TargetKind.Operator)] + public static SqlExpression TimeOnlyOperatorGreaterThanOrEqual( + [Type(typeof(TimeOnly))] SqlExpression d1, + [Type(typeof(TimeOnly))] SqlExpression d2) { - return SqlDml.DateTimeMinusDateTime(_this, value); + return d1 >= d2; } - [Compiler(typeof(DateTime), "Now", TargetKind.Static | TargetKind.PropertyGet)] - public static SqlExpression DateTimeNow() + [Compiler(typeof(TimeOnly), Operator.LessThan, TargetKind.Operator)] + public static SqlExpression TimeOnlyOperatorLessThan( + [Type(typeof(TimeOnly))] SqlExpression d1, + [Type(typeof(TimeOnly))] SqlExpression d2) { - return SqlDml.CurrentTimeStamp(); + return d1 < d2; } - [Compiler(typeof(DateTime), "Today", TargetKind.Static | TargetKind.PropertyGet)] - public static SqlExpression DateTimeToday() + [Compiler(typeof(TimeOnly), Operator.LessThanOrEqual, TargetKind.Operator)] + public static SqlExpression TimeOnlyOperatorLessThanOrEqual( + [Type(typeof(TimeOnly))] SqlExpression d1, + [Type(typeof(TimeOnly))] SqlExpression d2) { - return SqlDml.CurrentDate(); + return d1 <= d2; } +#endif // DO_DATEONLY + + #endregion + + [Compiler(typeof(DateTime), "Add")] + public static SqlExpression DateTimeAdd(SqlExpression _this, [Type(typeof(TimeSpan))] SqlExpression value) => + SqlDml.DateTimePlusInterval(_this, value); + + [Compiler(typeof(DateTime), "AddYears")] + public static SqlExpression DateTimeAddYears(SqlExpression _this, [Type(typeof(int))] SqlExpression value) => + SqlDml.DateTimeAddYears(_this, value); + + [Compiler(typeof(DateTime), "AddMonths")] + public static SqlExpression DateTimeAddMonths(SqlExpression _this, [Type(typeof(int))] SqlExpression value) => + SqlDml.DateTimeAddMonths(_this, value); + + [Compiler(typeof(DateTime), "AddDays")] + public static SqlExpression DateTimeAddDays(SqlExpression _this, [Type(typeof(double))] SqlExpression value) => + SqlDml.DateTimePlusInterval(_this, TimeSpanCompilers.TimeSpanFromDays(value)); + + [Compiler(typeof(DateTime), "AddHours")] + public static SqlExpression DateTimeAddHours(SqlExpression _this, [Type(typeof(double))] SqlExpression value) => + SqlDml.DateTimePlusInterval(_this, TimeSpanCompilers.TimeSpanFromHours(value)); + + [Compiler(typeof(DateTime), "AddMinutes")] + public static SqlExpression DateTimeAddMinutes(SqlExpression _this, [Type(typeof(double))] SqlExpression value) => + SqlDml.DateTimePlusInterval(_this, TimeSpanCompilers.TimeSpanFromMinutes(value)); + + [Compiler(typeof(DateTime), "AddSeconds")] + public static SqlExpression DateTimeAddSeconds(SqlExpression _this, [Type(typeof(double))] SqlExpression value) => + SqlDml.DateTimePlusInterval(_this, TimeSpanCompilers.TimeSpanFromSeconds(value)); + + [Compiler(typeof(DateTime), "AddMilliseconds")] + public static SqlExpression DateTimeAddMilliseconds(SqlExpression _this, [Type(typeof(double))] SqlExpression value) => + SqlDml.DateTimePlusInterval(_this, TimeSpanCompilers.TimeSpanFromMilliseconds(value)); + + [Compiler(typeof(DateTime), "Subtract")] + public static SqlExpression DateTimeSubtractTimeSpan(SqlExpression _this, [Type(typeof(TimeSpan))] SqlExpression value) => + SqlDml.DateTimeMinusInterval(_this, value); + + [Compiler(typeof(DateTime), "Subtract")] + public static SqlExpression DateTimeSubtractDateTime(SqlExpression _this, [Type(typeof(DateTime))] SqlExpression value) => + SqlDml.DateTimeMinusDateTime(_this, value); + + [Compiler(typeof(DateTime), "Now", TargetKind.Static | TargetKind.PropertyGet)] + public static SqlExpression DateTimeNow() => + SqlDml.CurrentTimeStamp(); + + [Compiler(typeof(DateTime), "Today", TargetKind.Static | TargetKind.PropertyGet)] + public static SqlExpression DateTimeToday() => + SqlDml.CurrentDate(); + [Compiler(typeof(DateTime), "IsLeapYear", TargetKind.Static | TargetKind.Method)] - public static SqlExpression DateTimeIsLeapYear([Type(typeof(int))] SqlExpression year) - { - return ((year % 4==0) && (year % 100!=0)) || (year % 400==0); - } + public static SqlExpression DateTimeIsLeapYear([Type(typeof(int))] SqlExpression year) => + ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); [Compiler(typeof(DateTime), "DaysInMonth", TargetKind.Static | TargetKind.Method)] public static SqlExpression DateTimeDaysInMonth( @@ -321,7 +422,7 @@ public static SqlExpression DateTimeDaysInMonth( var result = SqlDml.Case(); result.Add(SqlDml.In(month, SqlDml.Array(1, 3, 5, 7, 8, 10, 12)), 31); - result.Add(month==2, februaryCase); + result.Add(month == 2, februaryCase); result.Else = 30; return result; @@ -338,13 +439,36 @@ public static SqlExpression DateTimeToStringIso(SqlExpression _this, [Type(typeo { var stringValue = value as SqlLiteral; - if (stringValue==null) + if (stringValue == null) throw new NotSupportedException(Strings.ExTranslationOfDateTimeToStringWithArbitraryArgumentsIsNotSupported); - + if (!stringValue.Value.Equals("s")) throw new NotSupportedException(Strings.ExTranslationOfDateTimeToStringWithArbitraryArgumentsIsNotSupported); return SqlDml.DateTimeToStringIso(_this); } + +#if DO_DATEONLY + [Compiler(typeof(DateOnly), "AddYears")] + public static SqlExpression DateOnlyAddYears(SqlExpression _this, [Type(typeof(int))] SqlExpression value) => + SqlDml.DateTimeAddYears(_this, value); + + [Compiler(typeof(DateOnly), "AddMonths")] + public static SqlExpression DateOnlyAddMonths(SqlExpression _this, [Type(typeof(int))] SqlExpression value) => + SqlDml.DateTimeAddMonths(_this, value); + + [Compiler(typeof(DateOnly), "AddDays")] + public static SqlExpression DateOnlyAddDays(SqlExpression _this, [Type(typeof(int))] SqlExpression value) => + SqlDml.DateOnlyAddDays(_this, value); + + [Compiler(typeof(TimeOnly), "AddHours")] + public static SqlExpression TimeOnlyAddHours(SqlExpression _this, [Type(typeof(double))] SqlExpression value) => + SqlDml.TimeOnlyAddHours(_this, value); + + [Compiler(typeof(TimeOnly), "AddMinutes")] + public static SqlExpression TimeOnlyAddMinutes(SqlExpression _this, [Type(typeof(double))] SqlExpression value) => + SqlDml.TimeOnlyAddMinutes(_this, value); + +#endif // DO_DATEONLY } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.Helpers.cs b/Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.Helpers.cs index 470d7b3d64..e7c48caf3c 100644 --- a/Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.Helpers.cs +++ b/Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.Helpers.cs @@ -303,8 +303,18 @@ private SqlExpression GetOrderByExpression(SqlExpression expression, SortProvide } var columnType = columns[index].Type; - if (providerInfo.Supports(ProviderFeatures.DateTimeEmulation) && columnType == WellKnownTypes.DateTime) { - return SqlDml.Cast(expression, SqlType.DateTime); + if (providerInfo.Supports(ProviderFeatures.DateTimeEmulation)) { + if (columnType == WellKnownTypes.DateTime) { + return SqlDml.Cast(expression, SqlType.DateTime); + } +#if DO_DATEONLY + if (columnType == WellKnownTypes.DateOnly) { + return SqlDml.Cast(expression, SqlType.Date); + } + if (columnType == WellKnownTypes.TimeOnly) { + return SqlDml.Cast(expression, SqlType.Time); + } +#endif } if (providerInfo.Supports(ProviderFeatures.DateTimeOffsetEmulation) && columnType == WellKnownTypes.DateTimeOffset) { @@ -328,6 +338,22 @@ private SqlExpression GetJoinExpression(SqlExpression leftExpression, SqlExpress if (columnPair.Second.Type == WellKnownTypes.DateTime) { rightExpression = SqlDml.Cast(rightExpression, SqlType.DateTime); } + +#if DO_DATEONLY + if (columnPair.First.Type == WellKnownTypes.DateOnly) { + leftExpression = SqlDml.Cast(leftExpression, SqlType.Date); + } + else if (columnPair.First.Type == WellKnownTypes.TimeOnly) { + leftExpression = SqlDml.Cast(leftExpression, SqlType.Time); + } + + if (columnPair.Second.Type == WellKnownTypes.DateOnly) { + rightExpression = SqlDml.Cast(rightExpression, SqlType.Date); + } + else if (columnPair.Second.Type == WellKnownTypes.TimeOnly) { + rightExpression = SqlDml.Cast(rightExpression, SqlType.Time); + } +#endif } if (providerInfo.Supports(ProviderFeatures.DateTimeOffsetEmulation)) { diff --git a/Orm/Xtensive.Orm/Reflection/WellKnownTypes.cs b/Orm/Xtensive.Orm/Reflection/WellKnownTypes.cs index 6c4c876b67..9e0f7b524b 100644 --- a/Orm/Xtensive.Orm/Reflection/WellKnownTypes.cs +++ b/Orm/Xtensive.Orm/Reflection/WellKnownTypes.cs @@ -57,6 +57,12 @@ internal static class WellKnownTypes public static readonly Type NullableDateTime = typeof(DateTime?); public static readonly Type DateTimeOffset = typeof(DateTimeOffset); public static readonly Type NullableDateTimeOffset = typeof(DateTimeOffset?); +#if DO_DATEONLY + public static readonly Type DateOnly = typeof(DateOnly); + public static readonly Type TimeOnly = typeof(TimeOnly); + public static readonly Type NullableDateOnly = typeof(DateOnly?); + public static readonly Type NullableTimeOnly = typeof(TimeOnly?); +#endif public static readonly Type Guid = typeof(Guid); public static readonly Type NullableGuid = typeof(Guid?); diff --git a/Orm/Xtensive.Orm/Sql/Compiler/Internals/PostCompiler.cs b/Orm/Xtensive.Orm/Sql/Compiler/Internals/PostCompiler.cs index 36ed234611..24943d17ee 100644 --- a/Orm/Xtensive.Orm/Sql/Compiler/Internals/PostCompiler.cs +++ b/Orm/Xtensive.Orm/Sql/Compiler/Internals/PostCompiler.cs @@ -39,10 +39,7 @@ public override void Visit(TextNode node) public override void Visit(VariantNode node) { - if (configuration.AlternativeBranches.Contains(node.Id)) - VisitNodes(node.Alternative); - else - VisitNodes(node.Main); + VisitNodes(configuration.AlternativeBranches.Contains(node.Id) ? node.Alternative : node.Main); } public override void Visit(PlaceholderNode node) diff --git a/Orm/Xtensive.Orm/Sql/Compiler/SqlCompiler.cs b/Orm/Xtensive.Orm/Sql/Compiler/SqlCompiler.cs index eb24539d64..87bd7eecfd 100644 --- a/Orm/Xtensive.Orm/Sql/Compiler/SqlCompiler.cs +++ b/Orm/Xtensive.Orm/Sql/Compiler/SqlCompiler.cs @@ -1170,7 +1170,7 @@ public virtual void Visit(SqlFunctionCall node) { using (context.EnterScope(node)) { AppendTranslatedEntry(node); - + if (node.Arguments.Count > 0) { using (context.EnterCollectionScope()) { var argumentPosition = 0; diff --git a/Orm/Xtensive.Orm/Sql/Compiler/SqlTranslator.cs b/Orm/Xtensive.Orm/Sql/Compiler/SqlTranslator.cs index f57fe08b7c..d120961333 100644 --- a/Orm/Xtensive.Orm/Sql/Compiler/SqlTranslator.cs +++ b/Orm/Xtensive.Orm/Sql/Compiler/SqlTranslator.cs @@ -72,12 +72,16 @@ public abstract class SqlTranslator : SqlDriverBound /// public abstract string DateTimeFormatString { get; } + public virtual string DateOnlyFormatString => throw new NotImplementedException(); + /// /// Gets the time span format string. /// See for details. /// public abstract string TimeSpanFormatString { get; } + public virtual string TimeOnlyFormatString => throw new NotImplementedException(); + /// /// Gets the parameter prefix. /// @@ -1518,6 +1522,14 @@ public virtual void Translate(SqlCompilerContext context, object literalValue) case Guid: case byte[]: throw new NotSupportedException(string.Format(Strings.ExTranslationOfLiteralOfTypeXIsNotSupported, literalType.GetShortName())); +#if DO_DATEONLY + case DateOnly dateOnly: + output.Append(dateOnly.ToString(DateOnlyFormatString, DateTimeFormat)); + break; + case TimeOnly timeOnly: + output.Append(timeOnly.ToString(TimeOnlyFormatString, DateTimeFormat)); + break; +#endif default: _ = output.Append(literalValue.ToString()); break; diff --git a/Orm/Xtensive.Orm/Sql/Dml/SqlFunctionType.cs b/Orm/Xtensive.Orm/Sql/Dml/SqlFunctionType.cs index a5d4701383..01c9084846 100644 --- a/Orm/Xtensive.Orm/Sql/Dml/SqlFunctionType.cs +++ b/Orm/Xtensive.Orm/Sql/Dml/SqlFunctionType.cs @@ -64,6 +64,9 @@ public enum SqlFunctionType DateTimeConstruct, DateTimeAddYears, DateTimeAddMonths, + DateOnlyAddDays, + TimeOnlyAddHours, + TimeOnlyAddMinutes, DateTimeTruncate, DateTimeToStringIso, IntervalConstruct, @@ -81,6 +84,11 @@ public enum SqlFunctionType DateTimeOffsetToUtcTime, DateTimeToDateTimeOffset, +#if DO_DATEONLY + DateOnlyConstruct, + TimeOnlyConstruct, +#endif + // .NET like rounding functions RoundDecimalToEven, diff --git a/Orm/Xtensive.Orm/Sql/Info/DataTypeCollection.cs b/Orm/Xtensive.Orm/Sql/Info/DataTypeCollection.cs index 6209cb8d52..d99839c3dc 100644 --- a/Orm/Xtensive.Orm/Sql/Info/DataTypeCollection.cs +++ b/Orm/Xtensive.Orm/Sql/Info/DataTypeCollection.cs @@ -27,8 +27,7 @@ public class DataTypeCollection : LockableBase, IEnumerable /// The instance. public DataTypeInfo this[string nativeType] { - get - { + get { DataTypeInfo result; nativeTypes.TryGetValue(nativeType, out result); return result; @@ -41,8 +40,7 @@ public DataTypeInfo this[string nativeType] /// The instance. public DataTypeInfo this[SqlType sqlType] { - get - { + get { DataTypeInfo result; sqlTypes.TryGetValue(sqlType, out result); return result; @@ -112,7 +110,7 @@ public void Add(SqlType sqlType, DataTypeInfo dataTypeInfo) public DataTypeInfo Decimal { get; set; } /// - /// Floating point number data from –3.40E + 38 through 3.40E + 38. + /// Floating point number data from –3.40E + 38 through 3.40E + 38. /// Storage size is 4 bytes. /// public DataTypeInfo Float { get; set; } @@ -144,6 +142,11 @@ public void Add(SqlType sqlType, DataTypeInfo dataTypeInfo) /// public DataTypeInfo Interval { get; set; } +#if DO_DATEONLY + public DataTypeInfo DateOnly { get; set; } + public DataTypeInfo TimeOnly { get; set; } +#endif + /// /// Fixed-length Unicode character data of n characters. /// n must be a value from 1 through 4,000. Storage size is two times n bytes. @@ -195,7 +198,7 @@ public override void Lock(bool recursive) base.Lock(recursive); foreach (DataTypeInfo item in this) { - if (item==null) + if (item == null) continue; sqlTypes[item.Type] = item; foreach (var type in item.NativeTypes) @@ -236,6 +239,10 @@ IEnumerator IEnumerable.GetEnumerator() yield return VarBinaryMax; yield return Guid; yield return Interval; +#if DO_DATEONLY + yield return DateOnly; + yield return TimeOnly; +#endif yield break; } diff --git a/Orm/Xtensive.Orm/Sql/Info/ValueRange.Types.cs b/Orm/Xtensive.Orm/Sql/Info/ValueRange.Types.cs index e8c7569b24..02a2056845 100644 --- a/Orm/Xtensive.Orm/Sql/Info/ValueRange.Types.cs +++ b/Orm/Xtensive.Orm/Sql/Info/ValueRange.Types.cs @@ -1,6 +1,6 @@ -// Copyright (C) 2003-2010 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. +// Copyright (C) 2003-2022 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. // Created by: Denis Krjuchkov // Created: 2009.07.21 @@ -78,5 +78,10 @@ public partial class ValueRange /// public static readonly ValueRange TimeSpan = new ValueRange(System.TimeSpan.MinValue, System.TimeSpan.MaxValue); + +#if DO_DATEONLY + public static readonly ValueRange DateOnly = new(System.DateOnly.MinValue, System.DateOnly.MaxValue); + public static readonly ValueRange TimeOnly = new(System.TimeOnly.MinValue, System.TimeOnly.MaxValue); +#endif } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Sql/Internals/SqlValidator.cs b/Orm/Xtensive.Orm/Sql/Internals/SqlValidator.cs index e7d3891f93..54ec399a13 100644 --- a/Orm/Xtensive.Orm/Sql/Internals/SqlValidator.cs +++ b/Orm/Xtensive.Orm/Sql/Internals/SqlValidator.cs @@ -31,6 +31,10 @@ internal static class SqlValidator WellKnownTypes.DateTime, WellKnownTypes.DateTimeOffset, WellKnownTypes.TimeSpan, +#if DO_DATEONLY + WellKnownTypes.DateOnly, + WellKnownTypes.TimeOnly, +#endif WellKnownTypes.ByteArray, WellKnownTypes.Guid }; diff --git a/Orm/Xtensive.Orm/Sql/SqlDml.cs b/Orm/Xtensive.Orm/Sql/SqlDml.cs index df19d92fd3..39445b9e94 100644 --- a/Orm/Xtensive.Orm/Sql/SqlDml.cs +++ b/Orm/Xtensive.Orm/Sql/SqlDml.cs @@ -564,6 +564,29 @@ public static SqlFunctionCall DateTimeConstruct(SqlExpression year, SqlExpressio return new SqlFunctionCall(SqlFunctionType.DateTimeConstruct, year, month, day); } +#if DO_DATEONLY + public static SqlFunctionCall DateOnlyConstruct(SqlExpression year, SqlExpression month, SqlExpression day) + { + ArgumentNullException.ThrowIfNull(year); + ArgumentNullException.ThrowIfNull(month); + ArgumentNullException.ThrowIfNull(day); + SqlValidator.EnsureIsArithmeticExpression(year); + SqlValidator.EnsureIsArithmeticExpression(month); + SqlValidator.EnsureIsArithmeticExpression(day); + return new SqlFunctionCall(SqlFunctionType.DateOnlyConstruct, year, month, day); + } + + public static SqlFunctionCall TimeOnlyConstruct(SqlExpression hours, + SqlExpression minutes, + SqlExpression seconds, + SqlExpression milliseconds) + { + var m = milliseconds + 1000L * (seconds + 60L * (minutes + 60L * hours)); + var ticks = 10_000 * m; + return new SqlFunctionCall(SqlFunctionType.TimeOnlyConstruct, ticks); + } +#endif + public static SqlBinary DateTimePlusInterval(SqlExpression left, SqlExpression right) { ArgumentValidator.EnsureArgumentNotNull(left, "left"); @@ -599,6 +622,27 @@ public static SqlFunctionCall DateTimeAddMonths(SqlExpression source, SqlExpress return new SqlFunctionCall(SqlFunctionType.DateTimeAddMonths, source, months); } + public static SqlFunctionCall DateOnlyAddDays(SqlExpression source, SqlExpression days) + { + ArgumentValidator.EnsureArgumentNotNull(source, "source"); + ArgumentValidator.EnsureArgumentNotNull(days, "days"); + return new SqlFunctionCall(SqlFunctionType.DateOnlyAddDays, source, days); + } + + public static SqlFunctionCall TimeOnlyAddHours(SqlExpression source, SqlExpression hours) + { + ArgumentValidator.EnsureArgumentNotNull(source, "source"); + ArgumentValidator.EnsureArgumentNotNull(hours, "hours"); + return new SqlFunctionCall(SqlFunctionType.TimeOnlyAddHours, source, hours); + } + + public static SqlFunctionCall TimeOnlyAddMinutes(SqlExpression source, SqlExpression minutes) + { + ArgumentValidator.EnsureArgumentNotNull(source, "source"); + ArgumentValidator.EnsureArgumentNotNull(minutes, "minutes"); + return new SqlFunctionCall(SqlFunctionType.TimeOnlyAddMinutes, source, minutes); + } + public static SqlFunctionCall DateTimeToStringIso(SqlExpression expression) { ArgumentValidator.EnsureArgumentNotNull(expression, "expression"); diff --git a/Orm/Xtensive.Orm/Sql/SqlDriver.cs b/Orm/Xtensive.Orm/Sql/SqlDriver.cs index 107319c921..bf055dc4d8 100644 --- a/Orm/Xtensive.Orm/Sql/SqlDriver.cs +++ b/Orm/Xtensive.Orm/Sql/SqlDriver.cs @@ -421,6 +421,10 @@ private static void RegisterStandardMappings(TypeMappingRegistryBuilder builder) builder.Add(WellKnownTypes.TimeSpan, mapper.ReadTimeSpan, mapper.BindTimeSpan, mapper.MapTimeSpan); builder.Add(WellKnownTypes.Guid, mapper.ReadGuid, mapper.BindGuid, mapper.MapGuid); builder.Add(WellKnownTypes.ByteArray, mapper.ReadByteArray, mapper.BindByteArray, mapper.MapByteArray); +#if DO_DATEONLY + builder.Add(WellKnownTypes.DateOnly, mapper.ReadDateOnly, mapper.BindDateOnly, mapper.MapDateOnly); + builder.Add(WellKnownTypes.TimeOnly, mapper.ReadTimeOnly, mapper.BindTimeOnly, mapper.MapTimeOnly); +#endif } private static void RegisterStandardReverseMappings(TypeMappingRegistryBuilder builder) @@ -446,6 +450,10 @@ private static void RegisterStandardReverseMappings(TypeMappingRegistryBuilder b builder.AddReverse(SqlType.VarBinary, WellKnownTypes.ByteArray); builder.AddReverse(SqlType.VarBinaryMax, WellKnownTypes.ByteArray); builder.AddReverse(SqlType.Guid, WellKnownTypes.Guid); +#if DO_DATEONLY + builder.AddReverse(SqlType.Date, WellKnownTypes.DateOnly); + builder.AddReverse(SqlType.Time, WellKnownTypes.TimeOnly); +#endif } private Extractor BuildExtractor(SqlConnection connection) diff --git a/Orm/Xtensive.Orm/Sql/SqlType.cs b/Orm/Xtensive.Orm/Sql/SqlType.cs index 9cba773976..895a17a3b5 100644 --- a/Orm/Xtensive.Orm/Sql/SqlType.cs +++ b/Orm/Xtensive.Orm/Sql/SqlType.cs @@ -97,6 +97,20 @@ public struct SqlType : IEquatable /// public static readonly SqlType DateTimeOffset = new SqlType("DateTimeOffset"); + /// + /// Date from January 1, 1753 through December 31, 9999, + /// Storage size is 3 bytes. + /// + public static readonly SqlType Date = new SqlType("Date"); + + /// + /// Time data from to an accuracy of one three-hundredth of a second (equivalent to 3.33 + /// milliseconds or 0.00333 seconds). Values are rounded to increments + /// of .000, .003, or .007 seconds. + /// Storage size is 6 bytes. + /// + public static readonly SqlType Time = new SqlType("Time"); + /// /// Datetime interval. /// diff --git a/Orm/Xtensive.Orm/Sql/ValueTypeMapping/TypeMapper.cs b/Orm/Xtensive.Orm/Sql/ValueTypeMapping/TypeMapper.cs index ebf1c576fd..e47ddb0206 100644 --- a/Orm/Xtensive.Orm/Sql/ValueTypeMapping/TypeMapper.cs +++ b/Orm/Xtensive.Orm/Sql/ValueTypeMapping/TypeMapper.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2021 Xtensive LLC. +// Copyright (C) 2009-2022 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Denis Krjuchkov @@ -165,85 +165,53 @@ public virtual void BindByteArray(DbParameter parameter, object value) #region ReadXxx methods - public virtual object ReadBoolean(DbDataReader reader, int index) - { - return reader.GetBoolean(index); - } + public virtual object ReadBoolean(DbDataReader reader, int index) => + reader.GetBoolean(index); - public virtual object ReadChar(DbDataReader reader, int index) - { - return reader.GetString(index).SingleOrDefault(); - } + public virtual object ReadChar(DbDataReader reader, int index) => + reader.GetString(index).SingleOrDefault(); - public virtual object ReadString(DbDataReader reader, int index) - { - return reader.GetString(index); - } + public virtual object ReadString(DbDataReader reader, int index) => + reader.GetString(index); - public virtual object ReadByte(DbDataReader reader, int index) - { - return reader.GetByte(index); - } + public virtual object ReadByte(DbDataReader reader, int index) => + reader.GetByte(index); - public virtual object ReadSByte(DbDataReader reader, int index) - { - return Convert.ToSByte(reader[index]); - } + public virtual object ReadSByte(DbDataReader reader, int index) => + Convert.ToSByte(reader[index]); - public virtual object ReadShort(DbDataReader reader, int index) - { - return reader.GetInt16(index); - } + public virtual object ReadShort(DbDataReader reader, int index) => + reader.GetInt16(index); - public virtual object ReadUShort(DbDataReader reader, int index) - { - return Convert.ToUInt16(reader[index]); - } + public virtual object ReadUShort(DbDataReader reader, int index) => + Convert.ToUInt16(reader[index]); - public virtual object ReadInt(DbDataReader reader, int index) - { - return reader.GetInt32(index); - } + public virtual object ReadInt(DbDataReader reader, int index) => + reader.GetInt32(index); - public virtual object ReadUInt(DbDataReader reader, int index) - { - return Convert.ToUInt32(reader[index]); - } + public virtual object ReadUInt(DbDataReader reader, int index) => + Convert.ToUInt32(reader[index]); - public virtual object ReadLong(DbDataReader reader, int index) - { - return reader.GetInt64(index); - } + public virtual object ReadLong(DbDataReader reader, int index) => + reader.GetInt64(index); - public virtual object ReadULong(DbDataReader reader, int index) - { - return Convert.ToUInt64(reader[index]); - } + public virtual object ReadULong(DbDataReader reader, int index) => + Convert.ToUInt64(reader[index]); - public virtual object ReadFloat(DbDataReader reader, int index) - { - return reader.GetFloat(index); - } + public virtual object ReadFloat(DbDataReader reader, int index) => + reader.GetFloat(index); - public virtual object ReadDouble(DbDataReader reader, int index) - { - return reader.GetDouble(index); - } + public virtual object ReadDouble(DbDataReader reader, int index) => + reader.GetDouble(index); - public virtual object ReadDecimal(DbDataReader reader, int index) - { - return reader.GetDecimal(index); - } + public virtual object ReadDecimal(DbDataReader reader, int index) => + reader.GetDecimal(index); - public virtual object ReadDateTime(DbDataReader reader, int index) - { - return reader.GetDateTime(index); - } + public virtual object ReadDateTime(DbDataReader reader, int index) => + reader.GetDateTime(index); - public virtual object ReadDateTimeOffset(DbDataReader reader, int index) - { - return (DateTimeOffset) reader.GetValue(index); - } + public virtual object ReadDateTimeOffset(DbDataReader reader, int index) => + (DateTimeOffset) reader.GetValue(index); public virtual object ReadTimeSpan(DbDataReader reader, int index) { @@ -257,10 +225,8 @@ public virtual object ReadTimeSpan(DbDataReader reader, int index) return TimeSpan.FromTicks(value / 100); } - public virtual object ReadGuid(DbDataReader reader, int index) - { - return reader.GetGuid(index); - } + public virtual object ReadGuid(DbDataReader reader, int index) => + reader.GetGuid(index); public virtual object ReadByteArray(DbDataReader reader, int index) { @@ -282,70 +248,44 @@ public virtual object ReadByteArray(DbDataReader reader, int index) #region MapXxx methods - public virtual SqlValueType MapBoolean(int? length, int? precision, int? scale) - { - return new SqlValueType(SqlType.Boolean); - } + public virtual SqlValueType MapBoolean(int? length, int? precision, int? scale) => + new SqlValueType(SqlType.Boolean); - public virtual SqlValueType MapChar(int? length, int? precision, int? scale) - { - return new SqlValueType(SqlType.VarChar, 1); - } + public virtual SqlValueType MapChar(int? length, int? precision, int? scale) => + new SqlValueType(SqlType.VarChar, 1); - public virtual SqlValueType MapString(int? length, int? precision, int? scale) - { - return ChooseStreamType(SqlType.VarChar, SqlType.VarCharMax, length, VarCharMaxLength); - } + public virtual SqlValueType MapString(int? length, int? precision, int? scale) => + ChooseStreamType(SqlType.VarChar, SqlType.VarCharMax, length, VarCharMaxLength); - public virtual SqlValueType MapByte(int? length, int? precision, int? scale) - { - return new SqlValueType(SqlType.UInt8); - } + public virtual SqlValueType MapByte(int? length, int? precision, int? scale) => + new SqlValueType(SqlType.UInt8); - public virtual SqlValueType MapSByte(int? length, int? precision, int? scale) - { - return new SqlValueType(SqlType.Int8); - } + public virtual SqlValueType MapSByte(int? length, int? precision, int? scale) => + new SqlValueType(SqlType.Int8); - public virtual SqlValueType MapShort(int? length, int? precision, int? scale) - { - return new SqlValueType(SqlType.Int16); - } + public virtual SqlValueType MapShort(int? length, int? precision, int? scale) => + new SqlValueType(SqlType.Int16); - public virtual SqlValueType MapUShort(int? length, int? precision, int? scale) - { - return new SqlValueType(SqlType.UInt16); - } + public virtual SqlValueType MapUShort(int? length, int? precision, int? scale) => + new SqlValueType(SqlType.UInt16); - public virtual SqlValueType MapInt(int? length, int? precision, int? scale) - { - return new SqlValueType(SqlType.Int32); - } + public virtual SqlValueType MapInt(int? length, int? precision, int? scale) => + new SqlValueType(SqlType.Int32); - public virtual SqlValueType MapUInt(int? length, int? precision, int? scale) - { - return new SqlValueType(SqlType.UInt32); - } + public virtual SqlValueType MapUInt(int? length, int? precision, int? scale) => + new SqlValueType(SqlType.UInt32); - public virtual SqlValueType MapLong(int? length, int? precision, int? scale) - { - return new SqlValueType(SqlType.Int64); - } + public virtual SqlValueType MapLong(int? length, int? precision, int? scale) => + new SqlValueType(SqlType.Int64); - public virtual SqlValueType MapULong(int? length, int? precision, int? scale) - { - return new SqlValueType(SqlType.UInt64); - } + public virtual SqlValueType MapULong(int? length, int? precision, int? scale) => + new SqlValueType(SqlType.UInt64); - public virtual SqlValueType MapFloat(int? length, int? precision, int? scale) - { - return new SqlValueType(SqlType.Float); - } + public virtual SqlValueType MapFloat(int? length, int? precision, int? scale) => + new SqlValueType(SqlType.Float); - public virtual SqlValueType MapDouble(int? length, int? precision, int? scale) - { - return new SqlValueType(SqlType.Double); - } + public virtual SqlValueType MapDouble(int? length, int? precision, int? scale) => + new SqlValueType(SqlType.Double); public virtual SqlValueType MapDecimal(int? length, int? precision, int? scale) { @@ -363,31 +303,47 @@ public virtual SqlValueType MapDecimal(int? length, int? precision, int? scale) return new SqlValueType(SqlType.Decimal, null, null, precision, scale); } - public virtual SqlValueType MapDateTime(int? length, int? precision, int? scale) - { - return new SqlValueType(SqlType.DateTime); - } + public virtual SqlValueType MapDateTime(int? length, int? precision, int? scale) => + new SqlValueType(SqlType.DateTime); - public virtual SqlValueType MapDateTimeOffset(int? length, int? precision, int? scale) - { - return new SqlValueType(SqlType.DateTimeOffset); - } + public virtual SqlValueType MapDateTimeOffset(int? length, int? precision, int? scale) => + new SqlValueType(SqlType.DateTimeOffset); - public virtual SqlValueType MapTimeSpan(int? length, int? precision, int? scale) - { - return new SqlValueType(SqlType.Int64); - } + public virtual SqlValueType MapTimeSpan(int? length, int? precision, int? scale) => + new SqlValueType(SqlType.Int64); + + public virtual SqlValueType MapGuid(int? length, int? precision, int? scale) => + new SqlValueType(SqlType.Guid); + + public virtual SqlValueType MapByteArray(int? length, int? precision, int? scale) => + ChooseStreamType(SqlType.VarBinary, SqlType.VarBinaryMax, length, VarBinaryMaxLength); - public virtual SqlValueType MapGuid(int? length, int? precision, int? scale) +#if DO_DATEONLY + public virtual void BindDateOnly(DbParameter parameter, object value) { - return new SqlValueType(SqlType.Guid); + parameter.DbType = DbType.Date; + parameter.Value = value != null ? ((DateOnly)value).ToDateTime(TimeOnly.MinValue) : DBNull.Value; } - public virtual SqlValueType MapByteArray(int? length, int? precision, int? scale) + public virtual void BindTimeOnly(DbParameter parameter, object value) { - return ChooseStreamType(SqlType.VarBinary, SqlType.VarBinaryMax, length, VarBinaryMaxLength); + parameter.DbType = DbType.Time; + parameter.Value = value != null ? ((TimeOnly)value).ToTimeSpan() : DBNull.Value; } + public virtual object ReadDateOnly(DbDataReader reader, int index) => + DateOnly.FromDateTime(reader.GetFieldValue(index)); + + public virtual object ReadTimeOnly(DbDataReader reader, int index) => + TimeOnly.FromTimeSpan(reader.GetFieldValue(index)); + + public virtual SqlValueType MapDateOnly(int? length, int? precision, int? scale) => + new SqlValueType(SqlType.Date); + + public virtual SqlValueType MapTimeOnly(int? length, int? precision, int? scale) => + new SqlValueType(SqlType.Time); +#endif // DO_DATEONLY + #endregion protected static SqlValueType ChooseStreamType(SqlType varType, SqlType varMaxType, int? length, int? varTypeMaxLength) diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs index 96c05a0401..f467983803 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs @@ -11,7 +11,7 @@ namespace Xtensive.Tuples.Packed { internal abstract class PackedFieldAccessor { - public static readonly PackedFieldAccessor[] All = new PackedFieldAccessor[18]; + public static readonly PackedFieldAccessor[] All = new PackedFieldAccessor[20]; /// /// Getter delegate. @@ -587,4 +587,32 @@ public DateTimeOffsetFieldAccessor() : base(GetSize() * 8, 17) { } } + +#if DO_DATEONLY + internal sealed class DateOnlyFieldAccessor : ValueFieldAccessor + { + protected override DateOnly Decode(long value) => + DateOnly.FromDayNumber((int)value); + + protected override long Encode(DateOnly value) => + value.DayNumber; + + public DateOnlyFieldAccessor() + : base(sizeof(int) * 8, 18) + { } + } + + internal sealed class TimeOnlyFieldAccessor : ValueFieldAccessor + { + protected override TimeOnly Decode(long value) => + new TimeOnly(value); + + protected override long Encode(TimeOnly value) => + value.Ticks; + + public TimeOnlyFieldAccessor() + : base(sizeof(long) * 8, 19) + { } + } +#endif } diff --git a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs index e554c77124..6342d49e25 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs @@ -34,22 +34,28 @@ private ref struct Counters private static class ValueFieldAccessorResolver { - private static readonly ValueFieldAccessor BoolAccessor = new BooleanFieldAccessor(); - private static readonly ValueFieldAccessor ByteAccessor = new ByteFieldAccessor(); - private static readonly ValueFieldAccessor SByteAccessor = new SByteFieldAccessor(); - private static readonly ValueFieldAccessor Int16Accessor = new ShortFieldAccessor(); - private static readonly ValueFieldAccessor UInt16Accessor = new UShortFieldAccessor(); - private static readonly ValueFieldAccessor Int32Accessor = new IntFieldAccessor(); - private static readonly ValueFieldAccessor UInt32Accessor = new UIntFieldAccessor(); - private static readonly ValueFieldAccessor Int64Accessor = new LongFieldAccessor(); - private static readonly ValueFieldAccessor UInt64Accessor = new ULongFieldAccessor(); - private static readonly ValueFieldAccessor SingleAccessor = new FloatFieldAccessor(); - private static readonly ValueFieldAccessor DoubleAccessor = new DoubleFieldAccessor(); - private static readonly ValueFieldAccessor DateTimeAccessor = new DateTimeFieldAccessor(); - private static readonly ValueFieldAccessor TimeSpanAccessor = new TimeSpanFieldAccessor(); - private static readonly ValueFieldAccessor DecimalAccessor = new DecimalFieldAccessor(); - private static readonly ValueFieldAccessor GuidAccessor = new GuidFieldAccessor(); - private static readonly ValueFieldAccessor DateTimeOffsetAccessor = new DateTimeOffsetFieldAccessor(); + private static readonly ValueFieldAccessor + BoolAccessor = new BooleanFieldAccessor(), + ByteAccessor = new ByteFieldAccessor(), + SByteAccessor = new SByteFieldAccessor(), + Int16Accessor = new ShortFieldAccessor(), + UInt16Accessor = new UShortFieldAccessor(), + Int32Accessor = new IntFieldAccessor(), + UInt32Accessor = new UIntFieldAccessor(), + Int64Accessor = new LongFieldAccessor(), + UInt64Accessor = new ULongFieldAccessor(), + SingleAccessor = new FloatFieldAccessor(), + DoubleAccessor = new DoubleFieldAccessor(), + DateTimeAccessor = new DateTimeFieldAccessor(), + TimeSpanAccessor = new TimeSpanFieldAccessor(), + DecimalAccessor = new DecimalFieldAccessor(), + GuidAccessor = new GuidFieldAccessor(), + DateTimeOffsetAccessor = new DateTimeOffsetFieldAccessor() +#if DO_DATEONLY + , DateOnlyAccessor = new DateOnlyFieldAccessor() + , TimeOnlyAccessor = new TimeOnlyFieldAccessor() +#endif + ; private static readonly int NullableTypeMetadataToken = WellKnownTypes.NullableOfT.MetadataToken; @@ -74,6 +80,10 @@ ValueFieldAccessor ResolveByType(Type type) ReferenceEquals(type, WellKnownTypes.Double) ? DoubleAccessor : ReferenceEquals(type, WellKnownTypes.DateTime) ? DateTimeAccessor : ReferenceEquals(type, WellKnownTypes.TimeSpan) ? TimeSpanAccessor : +#if DO_DATEONLY + ReferenceEquals(type, WellKnownTypes.DateOnly) ? DateOnlyAccessor : + ReferenceEquals(type, WellKnownTypes.TimeOnly) ? TimeOnlyAccessor : +#endif ReferenceEquals(type, WellKnownTypes.Decimal) ? DecimalAccessor : ReferenceEquals(type, WellKnownTypes.Guid) ? GuidAccessor : ReferenceEquals(type, WellKnownTypes.DateTimeOffset) ? DateTimeOffsetAccessor : null; @@ -94,6 +104,10 @@ ValueFieldAccessor ResolveByNullableType(Type type) ReferenceEquals(type, WellKnownTypes.NullableDouble) ? DoubleAccessor : ReferenceEquals(type, WellKnownTypes.NullableDateTime) ? DateTimeAccessor : ReferenceEquals(type, WellKnownTypes.NullableTimeSpan) ? TimeSpanAccessor : +#if DO_DATEONLY + ReferenceEquals(type, WellKnownTypes.NullableDateOnly) ? DateOnlyAccessor : + ReferenceEquals(type, WellKnownTypes.NullableTimeOnly) ? TimeOnlyAccessor : +#endif ReferenceEquals(type, WellKnownTypes.NullableDecimal) ? DecimalAccessor : ReferenceEquals(type, WellKnownTypes.NullableGuid) ? GuidAccessor : ReferenceEquals(type, WellKnownTypes.NullableDateTimeOffset) ? DateTimeOffsetAccessor : null; diff --git a/Orm/Xtensive.Orm/Xtensive.Orm.csproj b/Orm/Xtensive.Orm/Xtensive.Orm.csproj index 0cf0e1de2b..7e8dc6e0e9 100644 --- a/Orm/Xtensive.Orm/Xtensive.Orm.csproj +++ b/Orm/Xtensive.Orm/Xtensive.Orm.csproj @@ -16,7 +16,7 @@ 1591 - TRACE;DEBUG + $(DefineConstants);TRACE;DEBUG $(TargetsForTfmSpecificContentInPackage);IncludeWeaverFiles From d7eb8adb123d939f8b9145fc8273e75afcd98ce1 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 19 Jul 2022 18:51:26 -0700 Subject: [PATCH 2/7] Some refactoring --- Directory.Build.props | 1 - .../Sql.Drivers.Firebird/v2_5/Compiler.cs | 6 ++-- .../Sql.Drivers.SqlServer/v09/Compiler.cs | 32 +++++++++---------- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 85f0735d62..7fa72fcfe8 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -100,7 +100,6 @@ - $(DefineConstants);DO_DATEONLY diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v2_5/Compiler.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v2_5/Compiler.cs index 4b2b8c5b8c..de0a60744e 100644 --- a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v2_5/Compiler.cs +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v2_5/Compiler.cs @@ -188,12 +188,12 @@ public override void Visit(SqlFunctionCall node) case SqlFunctionType.DateTimeAddMonths: Visit(DateAddMonth(node.Arguments[0], node.Arguments[1])); return; - case SqlFunctionType.DateOnlyAddDays: - Visit(DateAddDay(node.Arguments[0], node.Arguments[1])); - return; case SqlFunctionType.DateTimeAddYears: Visit(DateAddYear(node.Arguments[0], node.Arguments[1])); return; + case SqlFunctionType.DateOnlyAddDays: + Visit(DateAddDay(node.Arguments[0], node.Arguments[1])); + return; case SqlFunctionType.DateTimeConstruct: Visit(DateAddDay(DateAddMonth(DateAddYear(SqlDml.Cast(SqlDml.Literal(new DateTime(2001, 1, 1)), SqlType.DateTime), node.Arguments[0] - 2001), diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/Compiler.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/Compiler.cs index 5505da3655..dcd7a48e3f 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/Compiler.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/Compiler.cs @@ -161,10 +161,10 @@ public override void Visit(SqlFunctionCall node) return; case SqlFunctionType.Round: // Round should always be called with 2 arguments - if (node.Arguments.Count == 1) { + if (arguments.Count == 1) { Visit(SqlDml.FunctionCall( translator.TranslateToString(SqlFunctionType.Round), - node.Arguments[0], + arguments[0], SqlDml.Literal(0))); return; } @@ -174,31 +174,31 @@ public override void Visit(SqlFunctionCall node) // It's stupid, isn't it? Visit(SqlDml.FunctionCall( translator.TranslateToString(SqlFunctionType.Round), - node.Arguments[0], + arguments[0], SqlDml.Literal(0), SqlDml.Literal(1))); return; case SqlFunctionType.Substring: - if (node.Arguments.Count == 2) { - node = SqlDml.Substring(node.Arguments[0], node.Arguments[1]); - SqlExpression len = SqlDml.CharLength(node.Arguments[0]); - node.Arguments.Add(len); + if (arguments.Count == 2) { + node = SqlDml.Substring(node.Arguments[0], arguments[1]); + SqlExpression len = SqlDml.CharLength(arguments[0]); + arguments.Add(len); Visit(node); return; } break; case SqlFunctionType.IntervalToMilliseconds: - Visit(CastToLong(node.Arguments[0]) / NanosecondsPerMillisecond); + Visit(CastToLong(arguments[0]) / NanosecondsPerMillisecond); return; case SqlFunctionType.IntervalConstruct: case SqlFunctionType.IntervalToNanoseconds: - Visit(CastToLong(node.Arguments[0])); + Visit(CastToLong(arguments[0])); return; case SqlFunctionType.DateTimeAddMonths: - Visit(DateAddMonth(node.Arguments[0], node.Arguments[1])); + Visit(DateAddMonth(arguments[0], arguments[1])); return; case SqlFunctionType.DateTimeAddYears: - Visit(DateAddYear(node.Arguments[0], node.Arguments[1])); + Visit(DateAddYear(arguments[0], arguments[1])); return; case SqlFunctionType.DateOnlyAddDays: Visit(DateAddDay(arguments[0], arguments[1])); @@ -210,16 +210,16 @@ public override void Visit(SqlFunctionCall node) Visit(DateAddMinute(arguments[0], arguments[1])); return; case SqlFunctionType.DateTimeTruncate: - DateTimeTruncate(node.Arguments[0]).AcceptVisitor(this); + DateTimeTruncate(arguments[0]).AcceptVisitor(this); return; case SqlFunctionType.DateTimeConstruct: Visit(DateAddDay(DateAddMonth(DateAddYear(SqlDml.Literal(new DateTime(2001, 1, 1)), - node.Arguments[0] - 2001), - node.Arguments[1] - 1), - node.Arguments[2] - 1)); + arguments[0] - 2001), + arguments[1] - 1), + arguments[2] - 1)); return; case SqlFunctionType.DateTimeToStringIso: - Visit(DateTimeToStringIso(node.Arguments[0])); + Visit(DateTimeToStringIso(arguments[0])); return; } From cf29f28ae01fb1842e9fb02f8b7b8b108e0a8d02 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 19 Jul 2022 18:52:22 -0700 Subject: [PATCH 3/7] Update Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/ServerInfoProvider.cs Co-authored-by: Oleg Shuruev --- .../Sql.Drivers.SqlServer/v09/ServerInfoProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/ServerInfoProvider.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/ServerInfoProvider.cs index 29bf200f16..8e37d50e42 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/ServerInfoProvider.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/ServerInfoProvider.cs @@ -255,8 +255,8 @@ public override DataTypeCollection GetDataTypesInfo() "datetime", "smalldatetime"); #if DO_DATEONLY - types.DateOnly = DataTypeInfo.Range(SqlType.Date, common | index,new ValueRange(new DateOnly(1, 1, 1), new DateOnly(9999, 12, 31)), "date"); - types.TimeOnly = DataTypeInfo.Range(SqlType.Time, common | index,new ValueRange(TimeOnly.MinValue, TimeOnly.MaxValue), "time"); + types.DateOnly = DataTypeInfo.Range(SqlType.Date, common | index, new ValueRange(new DateOnly(1, 1, 1), new DateOnly(9999, 12, 31)), "date"); + types.TimeOnly = DataTypeInfo.Range(SqlType.Time, common | index, new ValueRange(TimeOnly.MinValue, TimeOnly.MaxValue), "time"); #endif types.Char = DataTypeInfo.Stream(SqlType.Char, common | index, 4000, "nchar", "char"); From c9e0948928b14ce69f874c77662bb728ea2f6e1b Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 19 Jul 2022 18:56:53 -0700 Subject: [PATCH 4/7] Code style --- .../Storage/SetFieldTest.cs | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Orm/Xtensive.Orm.Tests/Storage/SetFieldTest.cs b/Orm/Xtensive.Orm.Tests/Storage/SetFieldTest.cs index 0a33ea6034..885fddf024 100644 --- a/Orm/Xtensive.Orm.Tests/Storage/SetFieldTest.cs +++ b/Orm/Xtensive.Orm.Tests/Storage/SetFieldTest.cs @@ -62,24 +62,24 @@ public void CombinedTest() }; var book = new Book(); - AssertIsCalled (() => { book.Title = "A"; }); + AssertIsCalled(() => { book.Title = "A"; }); AssertIsNotCalled(() => { book.Title = "A"; }); - AssertIsCalled (() => { book.Date = new DateTime(1,2,3); }); - AssertIsNotCalled(() => { book.Date = new DateTime(1,2,3); }); + AssertIsCalled(() => { book.Date = new DateTime(1, 2, 3); }); + AssertIsNotCalled(() => { book.Date = new DateTime(1, 2, 3); }); #if DO_DATEONLY - AssertIsCalled (() => { book.DateOnly = new DateOnly(1,2,3); }); - AssertIsNotCalled(() => { book.DateOnly = new DateOnly(1,2,3); }); + AssertIsCalled(() => { book.DateOnly = new DateOnly(1, 2, 3); }); + AssertIsNotCalled(() => { book.DateOnly = new DateOnly(1, 2, 3); }); #endif - - var image = new byte[] {1, 2, 3}; - AssertIsCalled (() => { book.Image = image; }); - AssertIsCalled (() => { book.Image = image; }); + + var image = new byte[] { 1, 2, 3 }; + AssertIsCalled(() => { book.Image = image; }); + AssertIsCalled(() => { book.Image = image; }); AssertIsNotCalled(() => { book.Pair = null; }); - AssertIsCalled (() => { book.Pair = book; }); + AssertIsCalled(() => { book.Pair = book; }); AssertIsNotCalled(() => { book.Pair = book; }); - AssertIsCalled (() => { book.Pair = null; }); + AssertIsCalled(() => { book.Pair = null; }); AssertIsNotCalled(() => { book.Pair = null; }); } } @@ -99,7 +99,7 @@ private void AssertIsCalled(Action action) { int oldCallCount = fieldSetCallCount; action.Invoke(); - if (fieldSetCallCount==oldCallCount) + if (fieldSetCallCount == oldCallCount) Assert.Fail("Expected event didn't occur."); } @@ -107,7 +107,7 @@ private void AssertIsNotCalled(Action action) { int oldCallCount = fieldSetCallCount; action.Invoke(); - if (fieldSetCallCount!=oldCallCount) + if (fieldSetCallCount != oldCallCount) Assert.Fail("Event occurred, although it shouldn't."); } } From 97a2dd3ab72981fec9eded7343206eb9ea3b37bb Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 19 Jul 2022 18:58:49 -0700 Subject: [PATCH 5/7] use is null --- .../Orm/Linq/MemberCompilation/MemberCompilerProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm/Orm/Linq/MemberCompilation/MemberCompilerProvider.cs b/Orm/Xtensive.Orm/Orm/Linq/MemberCompilation/MemberCompilerProvider.cs index aa1a586aa6..d3bff30fb7 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/MemberCompilation/MemberCompilerProvider.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/MemberCompilation/MemberCompilerProvider.cs @@ -306,7 +306,7 @@ private static CompilerKey GetCompilerKey(MemberInfo member) if (canonicalMember is PropertyInfo sourceProperty) { canonicalMember = sourceProperty.GetGetMethod(); // GetGetMethod returns null in case of non public getter. - if (canonicalMember==null) { + if (canonicalMember is null) { return default; } } From 2e4e002dc8b407e8c79c5aa2c4e0d0fcd6cbbe07 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 19 Jul 2022 21:43:48 -0700 Subject: [PATCH 6/7] node.Arguments --- .../Sql.Drivers.SqlServer/v09/Compiler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/Compiler.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/Compiler.cs index dcd7a48e3f..ce6d97f9fd 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/Compiler.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/Compiler.cs @@ -153,7 +153,7 @@ public override void Visit(SqlFunctionCall node) var arguments = node.Arguments; switch (node.FunctionType) { case SqlFunctionType.CharLength: - (SqlDml.FunctionCall("DATALENGTH", node.Arguments) / 2).AcceptVisitor(this); + (SqlDml.FunctionCall("DATALENGTH", arguments) / 2).AcceptVisitor(this); return; case SqlFunctionType.PadLeft: case SqlFunctionType.PadRight: From 4b8160b247cbb30edcba683a090bdc819c8a6a19 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 19 Jul 2022 21:52:56 -0700 Subject: [PATCH 7/7] Update Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v10/ServerInfoProvider.cs Co-authored-by: Oleg Shuruev --- .../Sql.Drivers.SqlServer/v10/ServerInfoProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v10/ServerInfoProvider.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v10/ServerInfoProvider.cs index e4653b4f5c..e93baaa3a3 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v10/ServerInfoProvider.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v10/ServerInfoProvider.cs @@ -42,7 +42,7 @@ public override DataTypeCollection GetDataTypesInfo() #else types.DateTime = DataTypeInfo.Range(SqlType.DateTime, common | index, new ValueRange(new DateTime(1, 1, 1), new DateTime(9999, 12, 31)), - "datetime2", "datetime", "date", "time", "smalldatetime"); + "datetime2", "datetime", "smalldatetime", "date", "time"); #endif types.VarBinaryMax = DataTypeInfo.Regular(SqlType.VarBinaryMax, common, "varbinary(max)", "image");