未验证 提交 5316df8f 编写于 作者: S Shay Rojansky 提交者: GitHub

Multirange support for NodaTime (#2182)

Fixes #2178
上级 ed65c44c
......@@ -23,7 +23,7 @@
<ItemGroup>
<Compile Include="..\Shared\*.cs" />
<None Include="README.md" Pack="true" PackagePath="\"/>
<None Include="README.md" Pack="true" PackagePath="\" />
<None Include="build\**\*">
<Pack>True</Pack>
<PackagePath>build</PackagePath>
......
using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping;
// ReSharper disable once CheckNamespace
namespace Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal;
public class DateIntervalMultirangeMapping : NpgsqlTypeMapping
{
private readonly DateIntervalRangeMapping _dateIntervalRangeMapping;
public DateIntervalMultirangeMapping(Type clrType, DateIntervalRangeMapping dateIntervalRangeMapping)
: base("datemultirange", clrType, NpgsqlDbType.DateMultirange)
=> _dateIntervalRangeMapping = dateIntervalRangeMapping;
protected DateIntervalMultirangeMapping(RelationalTypeMappingParameters parameters, DateIntervalRangeMapping dateIntervalRangeMapping)
: base(parameters, NpgsqlDbType.DateMultirange)
=> _dateIntervalRangeMapping = dateIntervalRangeMapping;
protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters)
=> new DateIntervalMultirangeMapping(parameters, _dateIntervalRangeMapping);
public override RelationalTypeMapping Clone(string storeType, int? size)
=> new DateIntervalMultirangeMapping(Parameters.WithStoreTypeAndSize(storeType, size), _dateIntervalRangeMapping);
public override CoreTypeMapping Clone(ValueConverter? converter)
=> new DateIntervalMultirangeMapping(Parameters.WithComposedConverter(converter), _dateIntervalRangeMapping);
protected override string GenerateNonNullSqlLiteral(object value)
=> NpgsqlMultirangeTypeMapping.GenerateNonNullSqlLiteral(value, _dateIntervalRangeMapping, "datemultirange");
}
\ No newline at end of file
......@@ -4,7 +4,7 @@
// ReSharper disable once CheckNamespace
namespace Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal;
public class DateIntervalMapping : NpgsqlTypeMapping
public class DateIntervalRangeMapping : NpgsqlTypeMapping
{
private static readonly ConstructorInfo _constructorWithDates =
typeof(DateInterval).GetConstructor(new[] { typeof(LocalDate), typeof(LocalDate) })!;
......@@ -12,29 +12,32 @@ public class DateIntervalMapping : NpgsqlTypeMapping
private static readonly ConstructorInfo _localDateConstructor =
typeof(LocalDate).GetConstructor(new[] { typeof(int), typeof(int), typeof(int) })!;
public DateIntervalMapping()
public DateIntervalRangeMapping()
: base("daterange", typeof(DateInterval), NpgsqlDbType.DateRange)
{
}
protected DateIntervalMapping(RelationalTypeMappingParameters parameters)
protected DateIntervalRangeMapping(RelationalTypeMappingParameters parameters)
: base(parameters, NpgsqlDbType.DateRange)
{
}
protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters)
=> new DateIntervalMapping(parameters);
=> new DateIntervalRangeMapping(parameters);
public override RelationalTypeMapping Clone(string storeType, int? size)
=> new DateIntervalMapping(Parameters.WithStoreTypeAndSize(storeType, size));
=> new DateIntervalRangeMapping(Parameters.WithStoreTypeAndSize(storeType, size));
public override CoreTypeMapping Clone(ValueConverter? converter)
=> new DateIntervalMapping(Parameters.WithComposedConverter(converter));
=> new DateIntervalRangeMapping(Parameters.WithComposedConverter(converter));
protected override string GenerateNonNullSqlLiteral(object value)
=> $"'{GenerateEmbeddedNonNullSqlLiteral(value)}'::daterange";
protected override string GenerateEmbeddedNonNullSqlLiteral(object value)
{
var dateInverval = (DateInterval)value;
return $"'[{LocalDatePattern.Iso.Format(dateInverval.Start)},{LocalDatePattern.Iso.Format(dateInverval.End)}]'::daterange";
var dateInterval = (DateInterval)value;
return $"[{LocalDatePattern.Iso.Format(dateInterval.Start)},{LocalDatePattern.Iso.Format(dateInterval.End)}]";
}
public override Expression GenerateCodeLiteral(object value)
......
using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping;
// ReSharper disable once CheckNamespace
namespace Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal;
public class IntervalMultirangeMapping : NpgsqlTypeMapping
{
private readonly IntervalRangeMapping _intervalRangeMapping;
public IntervalMultirangeMapping(Type clrType, IntervalRangeMapping intervalRangeMapping)
: base("tstzmultirange", clrType, NpgsqlDbType.TimestampTzMultirange)
=> _intervalRangeMapping = intervalRangeMapping;
protected IntervalMultirangeMapping(RelationalTypeMappingParameters parameters, IntervalRangeMapping intervalRangeMapping)
: base(parameters, NpgsqlDbType.DateMultirange)
=> _intervalRangeMapping = intervalRangeMapping;
protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters)
=> new IntervalMultirangeMapping(parameters, _intervalRangeMapping);
public override RelationalTypeMapping Clone(string storeType, int? size)
=> new IntervalMultirangeMapping(Parameters.WithStoreTypeAndSize(storeType, size), _intervalRangeMapping);
public override CoreTypeMapping Clone(ValueConverter? converter)
=> new IntervalMultirangeMapping(Parameters.WithComposedConverter(converter), _intervalRangeMapping);
protected override string GenerateNonNullSqlLiteral(object value)
=> NpgsqlMultirangeTypeMapping.GenerateNonNullSqlLiteral(value, _intervalRangeMapping, "tstzmultirange");
}
\ No newline at end of file
// ReSharper disable once CheckNamespace
using System.Text;
using NodaTime.Text;
using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping;
// ReSharper disable once CheckNamespace
namespace Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal;
public class IntervalMapping : NpgsqlTypeMapping
public class IntervalRangeMapping : NpgsqlTypeMapping
{
private static readonly ConstructorInfo _constructor =
typeof(Interval).GetConstructor(new[] { typeof(Instant), typeof(Instant) })!;
......@@ -14,37 +15,49 @@ public class IntervalMapping : NpgsqlTypeMapping
private static readonly ConstructorInfo _constructorWithNulls =
typeof(Interval).GetConstructor(new[] { typeof(Instant?), typeof(Instant?) })!;
public IntervalMapping()
public IntervalRangeMapping()
: base("tstzrange", typeof(Interval), NpgsqlDbType.TimestampTzRange)
{
}
protected IntervalMapping(RelationalTypeMappingParameters parameters)
protected IntervalRangeMapping(RelationalTypeMappingParameters parameters)
: base(parameters, NpgsqlDbType.TimestampTzRange)
{
}
protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters)
=> new IntervalMapping(parameters);
=> new IntervalRangeMapping(parameters);
public override RelationalTypeMapping Clone(string storeType, int? size)
=> new IntervalMapping(Parameters.WithStoreTypeAndSize(storeType, size));
=> new IntervalRangeMapping(Parameters.WithStoreTypeAndSize(storeType, size));
public override CoreTypeMapping Clone(ValueConverter? converter)
=> new IntervalMapping(Parameters.WithComposedConverter(converter));
=> new IntervalRangeMapping(Parameters.WithComposedConverter(converter));
protected override string GenerateNonNullSqlLiteral(object value)
=> $"'{GenerateEmbeddedNonNullSqlLiteral(value)}'::tstzrange";
protected override string GenerateEmbeddedNonNullSqlLiteral(object value)
{
var interval = (Interval)value;
var start = interval.HasStart
? InstantPattern.ExtendedIso.Format(interval.Start)
: "";
var end = interval.HasEnd
? InstantPattern.ExtendedIso.Format(interval.End)
: "";
var stringBuilder = new StringBuilder("[");
if (interval.HasStart)
{
stringBuilder.Append(InstantPattern.ExtendedIso.Format(interval.Start));
}
stringBuilder.Append(',');
if (interval.HasEnd)
{
stringBuilder.Append(InstantPattern.ExtendedIso.Format(interval.End));
}
stringBuilder.Append(')');
return $"'[{start},{end})'::tstzrange";
return stringBuilder.ToString();
}
public override Expression GenerateCodeLiteral(object value)
......
......@@ -38,15 +38,34 @@ static NpgsqlNodaTimeTypeMappingSourcePlugin()
private readonly PeriodIntervalMapping _periodInterval = new();
private readonly DurationIntervalMapping _durationInterval = new();
// Built-in ranges
private readonly NpgsqlRangeTypeMapping _timestampLocalDateTimeRange;
private readonly NpgsqlRangeTypeMapping _legacyTimestampInstantRange;
private readonly NpgsqlRangeTypeMapping _timestamptzInstantRange;
private readonly NpgsqlRangeTypeMapping _timestamptzZonedDateTimeRange;
private readonly NpgsqlRangeTypeMapping _timestamptzOffsetDateTimeRange;
private readonly NpgsqlRangeTypeMapping _dateRange;
private readonly DateIntervalMapping _dateInterval = new();
private readonly IntervalMapping _interval = new();
private readonly DateIntervalRangeMapping _dateIntervalRange = new();
private readonly IntervalRangeMapping _intervalRange = new();
// Built-in multiranges
private readonly NpgsqlMultirangeTypeMapping _timestampLocalDateTimeMultirangeArray;
private readonly NpgsqlMultirangeTypeMapping _legacyTimestampInstantMultirangeArray;
private readonly NpgsqlMultirangeTypeMapping _timestamptzInstantMultirangeArray;
private readonly NpgsqlMultirangeTypeMapping _timestamptzZonedDateTimeMultirangeArray;
private readonly NpgsqlMultirangeTypeMapping _timestamptzOffsetDateTimeMultirangeArray;
private readonly NpgsqlMultirangeTypeMapping _dateRangeMultirangeArray;
private readonly DateIntervalMultirangeMapping _dateIntervalMultirangeArray;
private readonly IntervalMultirangeMapping _intervalMultirangeArray;
private readonly NpgsqlMultirangeTypeMapping _timestampLocalDateTimeMultirangeList;
private readonly NpgsqlMultirangeTypeMapping _legacyTimestampInstantMultirangeList;
private readonly NpgsqlMultirangeTypeMapping _timestamptzInstantMultirangeList;
private readonly NpgsqlMultirangeTypeMapping _timestamptzZonedDateTimeMultirangeList;
private readonly NpgsqlMultirangeTypeMapping _timestamptzOffsetDateTimeMultirangeList;
private readonly NpgsqlMultirangeTypeMapping _dateRangeMultirangeList;
private readonly DateIntervalMultirangeMapping _dateIntervalMultirangeList;
private readonly IntervalMultirangeMapping _intervalMultirangeList;
#endregion
......@@ -55,10 +74,10 @@ static NpgsqlNodaTimeTypeMappingSourcePlugin()
/// </summary>
public NpgsqlNodaTimeTypeMappingSourcePlugin(ISqlGenerationHelper sqlGenerationHelper)
{
_legacyTimestampInstantRange
= new NpgsqlRangeTypeMapping("tsrange", typeof(NpgsqlRange<Instant>), _legacyTimestampInstant, sqlGenerationHelper);
_timestampLocalDateTimeRange
= new NpgsqlRangeTypeMapping("tsrange", typeof(NpgsqlRange<LocalDateTime>), _timestampLocalDateTime, sqlGenerationHelper);
_legacyTimestampInstantRange
= new NpgsqlRangeTypeMapping("tsrange", typeof(NpgsqlRange<Instant>), _legacyTimestampInstant, sqlGenerationHelper);
_timestamptzInstantRange
= new NpgsqlRangeTypeMapping("tstzrange", typeof(NpgsqlRange<Instant>), _timestamptzInstant, sqlGenerationHelper);
_timestamptzZonedDateTimeRange
......@@ -68,6 +87,36 @@ public NpgsqlNodaTimeTypeMappingSourcePlugin(ISqlGenerationHelper sqlGenerationH
_dateRange
= new NpgsqlRangeTypeMapping("daterange", typeof(NpgsqlRange<LocalDate>), _date, sqlGenerationHelper);
_timestampLocalDateTimeMultirangeArray = new NpgsqlMultirangeTypeMapping(
"tsmultirange", typeof(NpgsqlRange<LocalDateTime>[]), _timestampLocalDateTimeRange, sqlGenerationHelper);
_legacyTimestampInstantMultirangeArray = new NpgsqlMultirangeTypeMapping(
"tsmultirange", typeof(NpgsqlRange<Instant>[]), _legacyTimestampInstantRange, sqlGenerationHelper);
_timestamptzInstantMultirangeArray = new NpgsqlMultirangeTypeMapping(
"tstzmultirange", typeof(NpgsqlRange<Instant>[]), _timestamptzInstantRange, sqlGenerationHelper);
_timestamptzZonedDateTimeMultirangeArray = new NpgsqlMultirangeTypeMapping(
"tstzmultirange", typeof(NpgsqlRange<ZonedDateTime>[]), _timestamptzZonedDateTimeRange, sqlGenerationHelper);
_timestamptzOffsetDateTimeMultirangeArray = new NpgsqlMultirangeTypeMapping(
"tstzmultirange", typeof(NpgsqlRange<OffsetDateTime>[]), _timestamptzOffsetDateTimeRange, sqlGenerationHelper);
_dateRangeMultirangeArray = new NpgsqlMultirangeTypeMapping(
"datemultirange", typeof(NpgsqlRange<LocalDate>[]), _dateRange, sqlGenerationHelper);
_dateIntervalMultirangeArray = new DateIntervalMultirangeMapping(typeof(DateInterval[]), _dateIntervalRange);
_intervalMultirangeArray = new IntervalMultirangeMapping(typeof(Interval[]), _intervalRange);
_timestampLocalDateTimeMultirangeList = new NpgsqlMultirangeTypeMapping(
"tsmultirange", typeof(List<NpgsqlRange<LocalDateTime>>), _timestampLocalDateTimeRange, sqlGenerationHelper);
_legacyTimestampInstantMultirangeList = new NpgsqlMultirangeTypeMapping(
"tsmultirange", typeof(List<NpgsqlRange<Instant>>), _legacyTimestampInstantRange, sqlGenerationHelper);
_timestamptzInstantMultirangeList = new NpgsqlMultirangeTypeMapping(
"tstzmultirange", typeof(List<NpgsqlRange<Instant>>), _timestamptzInstantRange, sqlGenerationHelper);
_timestamptzZonedDateTimeMultirangeList = new NpgsqlMultirangeTypeMapping(
"tstzmultirange", typeof(List<NpgsqlRange<ZonedDateTime>>), _timestamptzZonedDateTimeRange, sqlGenerationHelper);
_timestamptzOffsetDateTimeMultirangeList = new NpgsqlMultirangeTypeMapping(
"tstzmultirange", typeof(List<NpgsqlRange<OffsetDateTime>>), _timestamptzOffsetDateTimeRange, sqlGenerationHelper);
_dateRangeMultirangeList = new NpgsqlMultirangeTypeMapping(
"datemultirange", typeof(List<NpgsqlRange<LocalDate>>), _dateRange, sqlGenerationHelper);
_dateIntervalMultirangeList = new DateIntervalMultirangeMapping(typeof(List<DateInterval>), _dateIntervalRange);
_intervalMultirangeList = new IntervalMultirangeMapping(typeof(List<Interval>), _intervalRange);
var storeTypeMappings = new Dictionary<string, RelationalTypeMapping[]>(StringComparer.OrdinalIgnoreCase)
{
{
......@@ -88,8 +137,29 @@ public NpgsqlNodaTimeTypeMappingSourcePlugin(ISqlGenerationHelper sqlGenerationH
? new RelationalTypeMapping[] { _legacyTimestampInstantRange, _timestampLocalDateTimeRange }
: new RelationalTypeMapping[] { _timestampLocalDateTimeRange, _legacyTimestampInstantRange }
},
{ "tstzrange", new RelationalTypeMapping[] { _interval, _timestamptzInstantRange, _timestamptzZonedDateTimeRange, _timestamptzOffsetDateTimeRange } },
{ "daterange", new RelationalTypeMapping[] { _dateInterval, _dateRange } }
{ "tstzrange", new RelationalTypeMapping[] { _intervalRange, _timestamptzInstantRange, _timestamptzZonedDateTimeRange, _timestamptzOffsetDateTimeRange } },
{ "daterange", new RelationalTypeMapping[] { _dateIntervalRange, _dateRange } },
{ "tsmultirange", LegacyTimestampBehavior
? new RelationalTypeMapping[] { _legacyTimestampInstantMultirangeArray, _legacyTimestampInstantMultirangeList, _timestampLocalDateTimeMultirangeArray, _timestampLocalDateTimeMultirangeList }
: new RelationalTypeMapping[] { _timestampLocalDateTimeMultirangeArray, _timestampLocalDateTimeMultirangeList, _legacyTimestampInstantMultirangeArray, _legacyTimestampInstantMultirangeList }
},
{
"tstzmultirange", new RelationalTypeMapping[]
{
_intervalMultirangeArray, _intervalMultirangeList,
_timestamptzInstantMultirangeArray, _timestamptzInstantMultirangeList,
_timestamptzZonedDateTimeMultirangeArray, _timestamptzZonedDateTimeMultirangeList,
_timestamptzOffsetDateTimeMultirangeArray, _timestamptzOffsetDateTimeMultirangeList
}
},
{
"datemultirange", new RelationalTypeMapping[]
{
_dateIntervalMultirangeArray, _dateIntervalMultirangeList,
_dateRangeMultirangeArray, _dateRangeMultirangeList
}
}
};
// Set up aliases
......@@ -116,8 +186,24 @@ public NpgsqlNodaTimeTypeMappingSourcePlugin(ISqlGenerationHelper sqlGenerationH
{ typeof(NpgsqlRange<ZonedDateTime>), _timestamptzZonedDateTimeRange },
{ typeof(NpgsqlRange<OffsetDateTime>), _timestamptzOffsetDateTimeRange },
{ typeof(NpgsqlRange<LocalDate>), _dateRange },
{ typeof(DateInterval), _dateInterval },
{ typeof(Interval), _interval }
{ typeof(DateInterval), _dateIntervalRange },
{ typeof(Interval), _intervalRange },
{ typeof(NpgsqlRange<Instant>[]), LegacyTimestampBehavior ? _legacyTimestampInstantMultirangeArray : _timestamptzInstantMultirangeArray },
{ typeof(NpgsqlRange<LocalDateTime>[]), _timestampLocalDateTimeMultirangeArray },
{ typeof(NpgsqlRange<ZonedDateTime>[]), _timestamptzZonedDateTimeMultirangeArray },
{ typeof(NpgsqlRange<OffsetDateTime>[]), _timestamptzOffsetDateTimeMultirangeArray },
{ typeof(NpgsqlRange<LocalDate>[]), _dateRangeMultirangeArray },
{ typeof(DateInterval[]), _dateIntervalMultirangeArray },
{ typeof(Interval[]), _intervalMultirangeArray },
{ typeof(List<NpgsqlRange<Instant>>), LegacyTimestampBehavior ? _legacyTimestampInstantMultirangeList : _timestamptzInstantMultirangeList },
{ typeof(List<NpgsqlRange<LocalDateTime>>), _timestampLocalDateTimeMultirangeList },
{ typeof(List<NpgsqlRange<ZonedDateTime>>), _timestamptzZonedDateTimeMultirangeList },
{ typeof(List<NpgsqlRange<OffsetDateTime>>), _timestamptzOffsetDateTimeMultirangeList },
{ typeof(List<NpgsqlRange<LocalDate>>), _dateRangeMultirangeList },
{ typeof(List<DateInterval>), _dateIntervalMultirangeList },
{ typeof(List<Interval>), _intervalMultirangeList }
};
StoreTypeMappings = new ConcurrentDictionary<string, RelationalTypeMapping[]>(storeTypeMappings, StringComparer.OrdinalIgnoreCase);
......
......@@ -76,6 +76,9 @@ protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters p
=> new NpgsqlMultirangeTypeMapping(parameters, NpgsqlDbType, RangeMapping, _sqlGenerationHelper);
protected override string GenerateNonNullSqlLiteral(object value)
=> GenerateNonNullSqlLiteral(value, RangeMapping, StoreType);
public static string GenerateNonNullSqlLiteral(object value, RelationalTypeMapping rangeMapping, string multirangeStoreType)
{
var multirange = (IList)value;
......@@ -84,7 +87,7 @@ protected override string GenerateNonNullSqlLiteral(object value)
for (var i = 0; i < multirange.Count; i++)
{
sb.Append(RangeMapping.GenerateEmbeddedSqlLiteral(multirange[i]));
sb.Append(rangeMapping.GenerateEmbeddedSqlLiteral(multirange[i]));
if (i < multirange.Count - 1)
{
sb.Append(", ");
......@@ -92,7 +95,7 @@ protected override string GenerateNonNullSqlLiteral(object value)
}
sb.Append("}'::");
sb.Append(StoreType);
sb.Append(multirangeStoreType);
return sb.ToString();
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册