Skip to content

Commit 307f1b1

Browse files
committed
Map IPNetwork <-> cidr
Closes #3321
1 parent 091cead commit 307f1b1

File tree

10 files changed

+1027
-249
lines changed

10 files changed

+1027
-249
lines changed

src/EFCore.PG/Extensions/DbFunctionsExtensions/NpgsqlNetworkDbFunctionsExtensions.cs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,21 @@ public static int Subtract(this DbFunctions _, NpgsqlInet inet, NpgsqlInet other
372372
public static string Abbreviate(this DbFunctions _, NpgsqlInet inet)
373373
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Abbreviate)));
374374

375+
/// <summary>
376+
/// Returns the abbreviated display format as text.
377+
/// </summary>
378+
/// <param name="_">The <see cref="DbFunctions" /> instance.</param>
379+
/// <param name="cidr">The cidr to abbreviate.</param>
380+
/// <returns>
381+
/// The abbreviated display format as text.
382+
/// </returns>
383+
/// <exception cref="NotSupportedException">
384+
/// This method is only intended for use via SQL translation as part of an EF Core LINQ query.
385+
/// </exception>
386+
public static string Abbreviate(this DbFunctions _, IPNetwork cidr)
387+
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Abbreviate)));
388+
389+
#pragma warning disable CS0618 // NpgsqlCidr is obsolete, replaced by .NET IPNetwork
375390
/// <summary>
376391
/// Returns the abbreviated display format as text.
377392
/// </summary>
@@ -385,6 +400,7 @@ public static string Abbreviate(this DbFunctions _, NpgsqlInet inet)
385400
/// </exception>
386401
public static string Abbreviate(this DbFunctions _, NpgsqlCidr cidr)
387402
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Abbreviate)));
403+
#pragma warning restore CS0618
388404

389405
/// <summary>
390406
/// Returns the broadcast address for a network.
@@ -481,7 +497,7 @@ public static NpgsqlInet Netmask(this DbFunctions _, NpgsqlInet inet)
481497
/// <exception cref="NotSupportedException">
482498
/// This method is only intended for use via SQL translation as part of an EF Core LINQ query.
483499
/// </exception>
484-
public static NpgsqlCidr Network(this DbFunctions _, NpgsqlInet inet)
500+
public static IPNetwork Network(this DbFunctions _, NpgsqlInet inet)
485501
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Network)));
486502

487503
/// <summary>
@@ -499,6 +515,22 @@ public static NpgsqlCidr Network(this DbFunctions _, NpgsqlInet inet)
499515
public static NpgsqlInet SetMaskLength(this DbFunctions _, NpgsqlInet inet, int length)
500516
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(SetMaskLength)));
501517

518+
/// <summary>
519+
/// Sets the length of the subnet mask.
520+
/// </summary>
521+
/// <param name="_">The <see cref="DbFunctions" /> instance.</param>
522+
/// <param name="cidr">The cidr to modify.</param>
523+
/// <param name="length">The subnet mask length to set.</param>
524+
/// <returns>
525+
/// The network with a subnet mask of the specified length.
526+
/// </returns>
527+
/// <exception cref="NotSupportedException">
528+
/// This method is only intended for use via SQL translation as part of an EF Core LINQ query.
529+
/// </exception>
530+
public static IPNetwork SetMaskLength(this DbFunctions _, IPNetwork cidr, int length)
531+
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(SetMaskLength)));
532+
533+
#pragma warning disable CS0618 // NpgsqlCidr is obsolete, replaced by .NET IPNetwork
502534
/// <summary>
503535
/// Sets the length of the subnet mask.
504536
/// </summary>
@@ -513,6 +545,7 @@ public static NpgsqlInet SetMaskLength(this DbFunctions _, NpgsqlInet inet, int
513545
/// </exception>
514546
public static NpgsqlCidr SetMaskLength(this DbFunctions _, NpgsqlCidr cidr, int length)
515547
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(SetMaskLength)));
548+
#pragma warning restore CS0618
516549

517550
/// <summary>
518551
/// Extracts the IP address and subnet mask as text.
@@ -555,7 +588,7 @@ public static bool SameFamily(this DbFunctions _, NpgsqlInet inet, NpgsqlInet ot
555588
/// <exception cref="NotSupportedException">
556589
/// This method is only intended for use via SQL translation as part of an EF Core LINQ query.
557590
/// </exception>
558-
public static NpgsqlCidr Merge(this DbFunctions _, NpgsqlInet inet, NpgsqlInet other)
591+
public static IPNetwork Merge(this DbFunctions _, NpgsqlInet inet, NpgsqlInet other)
559592
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Merge)));
560593

561594
/// <summary>

src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlNetworkTranslator.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,12 @@ public NpgsqlNetworkTranslator(
7070
return TranslateInetExtensionMethod(method, arguments);
7171
}
7272

73-
if (paramType == typeof(NpgsqlCidr))
73+
#pragma warning disable CS0618 // NpgsqlCidr is obsolete, replaced by .NET IPNetwork
74+
if (paramType == typeof(IPNetwork) || paramType == typeof(NpgsqlCidr))
7475
{
7576
return TranslateCidrExtensionMethod(method, arguments);
7677
}
78+
#pragma warning restore CS0618
7779

7880
if (paramType == typeof(PhysicalAddress))
7981
{

src/EFCore.PG/Query/Internal/NpgsqlQuerySqlGenerator.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -496,11 +496,11 @@ protected virtual Expression VisitPgBinary(PgBinaryExpression binaryExpression)
496496
binaryExpression.OperatorType switch
497497
{
498498
PgExpressionType.Contains
499-
when binaryExpression.Left.TypeMapping is NpgsqlInetTypeMapping or NpgsqlCidrTypeMapping
499+
when binaryExpression.Left.TypeMapping is NpgsqlInetTypeMapping or NpgsqlCidrTypeMapping or NpgsqlLegacyCidrTypeMapping
500500
=> ">>",
501501

502502
PgExpressionType.ContainedBy
503-
when binaryExpression.Left.TypeMapping is NpgsqlInetTypeMapping or NpgsqlCidrTypeMapping
503+
when binaryExpression.Left.TypeMapping is NpgsqlInetTypeMapping or NpgsqlCidrTypeMapping or NpgsqlLegacyCidrTypeMapping
504504
=> "<<",
505505

506506
PgExpressionType.Contains => "@>",

src/EFCore.PG/Query/Internal/NpgsqlSqlTranslatingExpressionVisitor.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,11 @@ protected override Expression VisitUnary(UnaryExpression unaryExpression)
188188
// implicit conversion operator to NpgsqlInet. So remove that cast as well.
189189
case ExpressionType.Convert
190190
when unaryExpression.Type == typeof(NpgsqlInet)
191-
&& (unaryExpression.Operand.Type == typeof(IPAddress) || unaryExpression.Operand.Type == typeof(NpgsqlCidr)):
191+
&& (unaryExpression.Operand.Type == typeof(IPAddress)
192+
|| unaryExpression.Operand.Type == typeof(IPNetwork)
193+
#pragma warning disable CS0618 // NpgsqlCidr is obsolete, replaced by .NET IPNetwork
194+
|| unaryExpression.Operand.Type == typeof(NpgsqlCidr)):
195+
#pragma warning restore CS0618
192196
return Visit(unaryExpression.Operand);
193197
}
194198

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
using System.Net;
2+
using System.Text.Json;
3+
using Microsoft.EntityFrameworkCore.Storage.Json;
4+
5+
namespace Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping;
6+
7+
#pragma warning disable CS0618 // NpgsqlCidr is obsolete, replaced by .NET IPNetwork
8+
9+
/// <summary>
10+
/// The type mapping for the PostgreSQL cidr type.
11+
/// </summary>
12+
/// <remarks>
13+
/// See: https://www.postgresql.org/docs/current/static/datatype-net-types.html#DATATYPE-CIDR
14+
/// </remarks>
15+
public class NpgsqlLegacyCidrTypeMapping : NpgsqlTypeMapping
16+
{
17+
/// <summary>
18+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
19+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
20+
/// any release. You should only use it directly in your code with extreme caution and knowing that
21+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
22+
/// </summary>
23+
public static NpgsqlLegacyCidrTypeMapping Default { get; } = new();
24+
25+
/// <summary>
26+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
27+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
28+
/// any release. You should only use it directly in your code with extreme caution and knowing that
29+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
30+
/// </summary>
31+
public NpgsqlLegacyCidrTypeMapping()
32+
: base("cidr", typeof(NpgsqlCidr), NpgsqlDbType.Cidr, JsonCidrLegacyReaderWriter.Instance)
33+
{
34+
}
35+
36+
/// <summary>
37+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
38+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
39+
/// any release. You should only use it directly in your code with extreme caution and knowing that
40+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
41+
/// </summary>
42+
protected NpgsqlLegacyCidrTypeMapping(RelationalTypeMappingParameters parameters)
43+
: base(parameters, NpgsqlDbType.Cidr)
44+
{
45+
}
46+
47+
/// <summary>
48+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
49+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
50+
/// any release. You should only use it directly in your code with extreme caution and knowing that
51+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
52+
/// </summary>
53+
protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters)
54+
=> new NpgsqlLegacyCidrTypeMapping(parameters);
55+
56+
/// <summary>
57+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
58+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
59+
/// any release. You should only use it directly in your code with extreme caution and knowing that
60+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
61+
/// </summary>
62+
protected override string GenerateNonNullSqlLiteral(object value)
63+
{
64+
var cidr = (NpgsqlCidr)value;
65+
return $"CIDR '{cidr.Address}/{cidr.Netmask}'";
66+
}
67+
68+
/// <summary>
69+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
70+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
71+
/// any release. You should only use it directly in your code with extreme caution and knowing that
72+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
73+
/// </summary>
74+
public override Expression GenerateCodeLiteral(object value)
75+
{
76+
var cidr = (NpgsqlCidr)value;
77+
return Expression.New(
78+
NpgsqlCidrConstructor,
79+
Expression.Call(ParseMethod, Expression.Constant(cidr.Address.ToString())),
80+
Expression.Constant(cidr.Netmask));
81+
}
82+
83+
private static readonly MethodInfo ParseMethod = typeof(IPAddress).GetMethod("Parse", [typeof(string)])!;
84+
85+
private static readonly ConstructorInfo NpgsqlCidrConstructor =
86+
typeof(NpgsqlCidr).GetConstructor([typeof(IPAddress), typeof(byte)])!;
87+
88+
/// <summary>
89+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
90+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
91+
/// any release. You should only use it directly in your code with extreme caution and knowing that
92+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
93+
/// </summary>
94+
public sealed class JsonCidrLegacyReaderWriter : JsonValueReaderWriter<NpgsqlCidr>
95+
{
96+
private static readonly PropertyInfo InstanceProperty = typeof(JsonCidrLegacyReaderWriter).GetProperty(nameof(Instance))!;
97+
98+
/// <summary>
99+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
100+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
101+
/// any release. You should only use it directly in your code with extreme caution and knowing that
102+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
103+
/// </summary>
104+
public static JsonCidrLegacyReaderWriter Instance { get; } = new();
105+
106+
/// <summary>
107+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
108+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
109+
/// any release. You should only use it directly in your code with extreme caution and knowing that
110+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
111+
/// </summary>
112+
public override NpgsqlCidr FromJsonTyped(ref Utf8JsonReaderManager manager, object? existingObject = null)
113+
=> new(manager.CurrentReader.GetString()!);
114+
115+
/// <summary>
116+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
117+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
118+
/// any release. You should only use it directly in your code with extreme caution and knowing that
119+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
120+
/// </summary>
121+
public override void ToJsonTyped(Utf8JsonWriter writer, NpgsqlCidr value)
122+
=> writer.WriteStringValue(value.ToString());
123+
124+
/// <inheritdoc />
125+
public override Expression ConstructorExpression => Expression.Property(null, InstanceProperty);
126+
}
127+
}

src/EFCore.PG/Storage/Internal/Mapping/NpgsqlCidrTypeMapping.cs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public class NpgsqlCidrTypeMapping : NpgsqlTypeMapping
2727
/// doing so can result in application failures when updating to a new Entity Framework Core release.
2828
/// </summary>
2929
public NpgsqlCidrTypeMapping()
30-
: base("cidr", typeof(NpgsqlCidr), NpgsqlDbType.Cidr, JsonCidrReaderWriter.Instance)
30+
: base("cidr", typeof(IPNetwork), NpgsqlDbType.Cidr, JsonCidrReaderWriter.Instance)
3131
{
3232
}
3333

@@ -59,8 +59,8 @@ protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters p
5959
/// </summary>
6060
protected override string GenerateNonNullSqlLiteral(object value)
6161
{
62-
var cidr = (NpgsqlCidr)value;
63-
return $"CIDR '{cidr.Address}/{cidr.Netmask}'";
62+
var ipNetwork = (IPNetwork)value;
63+
return $"CIDR '{ipNetwork.BaseAddress}/{ipNetwork.PrefixLength}'";
6464
}
6565

6666
/// <summary>
@@ -71,25 +71,25 @@ protected override string GenerateNonNullSqlLiteral(object value)
7171
/// </summary>
7272
public override Expression GenerateCodeLiteral(object value)
7373
{
74-
var cidr = (NpgsqlCidr)value;
74+
var cidr = (IPNetwork)value;
7575
return Expression.New(
7676
NpgsqlCidrConstructor,
77-
Expression.Call(ParseMethod, Expression.Constant(cidr.Address.ToString())),
78-
Expression.Constant(cidr.Netmask));
77+
Expression.Call(ParseMethod, Expression.Constant(cidr.BaseAddress.ToString())),
78+
Expression.Constant(cidr.PrefixLength));
7979
}
8080

8181
private static readonly MethodInfo ParseMethod = typeof(IPAddress).GetMethod("Parse", [typeof(string)])!;
8282

8383
private static readonly ConstructorInfo NpgsqlCidrConstructor =
84-
typeof(NpgsqlCidr).GetConstructor([typeof(IPAddress), typeof(byte)])!;
84+
typeof(IPNetwork).GetConstructor([typeof(IPAddress), typeof(int)])!;
8585

8686
/// <summary>
8787
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
8888
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
8989
/// any release. You should only use it directly in your code with extreme caution and knowing that
9090
/// doing so can result in application failures when updating to a new Entity Framework Core release.
9191
/// </summary>
92-
public sealed class JsonCidrReaderWriter : JsonValueReaderWriter<NpgsqlCidr>
92+
public sealed class JsonCidrReaderWriter : JsonValueReaderWriter<IPNetwork>
9393
{
9494
private static readonly PropertyInfo InstanceProperty = typeof(JsonCidrReaderWriter).GetProperty(nameof(Instance))!;
9595

@@ -107,17 +107,17 @@ public sealed class JsonCidrReaderWriter : JsonValueReaderWriter<NpgsqlCidr>
107107
/// any release. You should only use it directly in your code with extreme caution and knowing that
108108
/// doing so can result in application failures when updating to a new Entity Framework Core release.
109109
/// </summary>
110-
public override NpgsqlCidr FromJsonTyped(ref Utf8JsonReaderManager manager, object? existingObject = null)
111-
=> new(manager.CurrentReader.GetString()!);
110+
public override IPNetwork FromJsonTyped(ref Utf8JsonReaderManager manager, object? existingObject = null)
111+
=> IPNetwork.Parse(manager.CurrentReader.GetString()!);
112112

113113
/// <summary>
114114
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
115115
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
116116
/// any release. You should only use it directly in your code with extreme caution and knowing that
117117
/// doing so can result in application failures when updating to a new Entity Framework Core release.
118118
/// </summary>
119-
public override void ToJsonTyped(Utf8JsonWriter writer, NpgsqlCidr value)
120-
=> writer.WriteStringValue(value.ToString());
119+
public override void ToJsonTyped(Utf8JsonWriter writer, IPNetwork ipNetwork)
120+
=> writer.WriteStringValue(ipNetwork.ToString());
121121

122122
/// <inheritdoc />
123123
public override Expression ConstructorExpression => Expression.Property(null, InstanceProperty);

src/EFCore.PG/Storage/Internal/NpgsqlTypeMappingSource.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ static NpgsqlTypeMappingSource()
115115
private readonly NpgsqlMacaddr8TypeMapping _macaddr8 = NpgsqlMacaddr8TypeMapping.Default;
116116
private readonly NpgsqlInetTypeMapping _inetAsIPAddress = NpgsqlInetTypeMapping.Default;
117117
private readonly NpgsqlInetTypeMapping _inetAsNpgsqlInet = new(typeof(NpgsqlInet));
118-
private readonly NpgsqlCidrTypeMapping _cidr = NpgsqlCidrTypeMapping.Default;
118+
private readonly NpgsqlCidrTypeMapping _cidrAsIPNetwork = NpgsqlCidrTypeMapping.Default;
119+
private readonly NpgsqlLegacyCidrTypeMapping _cidrAsNpgsqlCidr = NpgsqlLegacyCidrTypeMapping.Default;
119120

120121
// Built-in geometric types
121122
private readonly NpgsqlPointTypeMapping _point = NpgsqlPointTypeMapping.Default;
@@ -261,7 +262,7 @@ public NpgsqlTypeMappingSource(
261262
{ "macaddr", [_macaddr] },
262263
{ "macaddr8", [_macaddr8] },
263264
{ "inet", [_inetAsIPAddress, _inetAsNpgsqlInet] },
264-
{ "cidr", [_cidr] },
265+
{ "cidr", [_cidrAsIPNetwork, _cidrAsNpgsqlCidr] },
265266
{ "point", [_point] },
266267
{ "box", [_box] },
267268
{ "line", [_line] },
@@ -324,7 +325,10 @@ public NpgsqlTypeMappingSource(
324325
{ typeof(PhysicalAddress), _macaddr },
325326
{ typeof(IPAddress), _inetAsIPAddress },
326327
{ typeof(NpgsqlInet), _inetAsNpgsqlInet },
327-
{ typeof(NpgsqlCidr), _cidr },
328+
{ typeof(IPNetwork), _cidrAsIPNetwork },
329+
#pragma warning disable CS0618 // NpgsqlCidr is obsolete, replaced by .NET IPNetwork
330+
{ typeof(NpgsqlCidr), _cidrAsNpgsqlCidr },
331+
#pragma warning restore CS0618
328332
{ typeof(BitArray), _varbit },
329333
{ typeof(ImmutableDictionary<string, string>), _immutableHstore },
330334
{ typeof(Dictionary<string, string>), _hstore },

0 commit comments

Comments
 (0)