diff --git a/Directory.Build.props b/Directory.Build.props
index 5b17ca697b..90b60e781e 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -128,4 +128,9 @@
+
+
+
+ $(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 82a5c02c26..cd9fb159f6 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
@@ -190,6 +190,9 @@ public override void Visit(SqlFunctionCall node)
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.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 1a811ecf3c..fa55be43ee 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.SqlServer/Sql.Drivers.SqlServer/v09/Compiler.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/Compiler.cs
index 6d1ce50ad8..be942201c4 100644
--- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/Compiler.cs
+++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/Compiler.cs
@@ -150,9 +150,10 @@ 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);
+ (SqlDml.FunctionCall("DATALENGTH", arguments) / 2).AcceptVisitor(this);
return;
case SqlFunctionType.PadLeft:
case SqlFunctionType.PadRight:
@@ -160,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;
}
@@ -173,42 +174,51 @@ 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) {
- SqlExpression len = SqlDml.CharLength(node.Arguments[0]);
- node = SqlDml.Substring(node.Arguments[0], node.Arguments[1], len);
+ if (arguments.Count == 2) {
+ SqlExpression len = SqlDml.CharLength(arguments[0]);
+ node = SqlDml.Substring(arguments[0], arguments[1], 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]));
+ 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);
+ 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;
}
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 c3368bf6f8..3910cf8f7e 100644
--- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/ServerInfoProvider.cs
+++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/ServerInfoProvider.cs
@@ -252,9 +252,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..e93baaa3a3 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", "smalldatetime", "date", "time");
+#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/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..885fddf024 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; }
@@ -57,19 +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); });
-
- var image = new byte[] {1, 2, 3};
- AssertIsCalled (() => { book.Image = image; });
- AssertIsCalled (() => { book.Image = image; });
+ 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; });
+ 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; });
}
}
@@ -89,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.");
}
@@ -97,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.");
}
}
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 ddb897a6c1..daec66375e 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 de88d6c07c..65f947022d 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,11 +303,10 @@ 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) {
+ if (canonicalMember is null) {
return default;
}
}
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 c007b5e345..8de00d9e56 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 7656b99a1d..d35ec9918a 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 81db08cedf..84a4b1f6ee 100644
--- a/Orm/Xtensive.Orm/Sql/Compiler/Internals/PostCompiler.cs
+++ b/Orm/Xtensive.Orm/Sql/Compiler/Internals/PostCompiler.cs
@@ -40,10 +40,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 295ce593bf..d682a2fcf3 100644
--- a/Orm/Xtensive.Orm/Sql/Compiler/SqlCompiler.cs
+++ b/Orm/Xtensive.Orm/Sql/Compiler/SqlCompiler.cs
@@ -1184,7 +1184,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 2908b3fcd3..71c9ee00f2 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 101e121a0d..3ff469a757 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 39310bf55c..955b9560f9 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;