-
Notifications
You must be signed in to change notification settings - Fork 225
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds support for PostgreSQL network address (inet/cidr/macaddr) opera…
…tors.
- Loading branch information
1 parent
5655b1c
commit 5842fad
Showing
6 changed files
with
521 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
#region License | ||
|
||
// The PostgreSQL License | ||
// | ||
// Copyright (C) 2016 The Npgsql Development Team | ||
// | ||
// Permission to use, copy, modify, and distribute this software and its | ||
// documentation for any purpose, without fee, and without a written | ||
// agreement is hereby granted, provided that the above copyright notice | ||
// and this paragraph and the following two paragraphs appear in all copies. | ||
// | ||
// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY | ||
// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, | ||
// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS | ||
// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF | ||
// THE POSSIBILITY OF SUCH DAMAGE. | ||
// | ||
// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES, | ||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | ||
// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS | ||
// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS | ||
// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | ||
|
||
#endregion | ||
|
||
using System; | ||
using System.Net; | ||
using NpgsqlTypes; | ||
|
||
namespace Npgsql.EntityFrameworkCore.PostgreSQL | ||
{ | ||
/// <summary> | ||
/// Provides extension methods supporting PostgreSQL network address operator translation. | ||
/// </summary> | ||
public static class NpgsqlNetworkAddressExtensions | ||
{ | ||
/// <summary> | ||
/// Determines whether an <see cref="IPAddress"/> contains another <see cref="IPAddress"/>. | ||
/// </summary> | ||
/// <param name="ipAddress">The IP address to search.</param> | ||
/// <param name="other">The IP address to locate.</param> | ||
/// <returns> | ||
/// <value>true</value> if the <see cref="IPAddress"/> contains the other <see cref="IPAddress"/>; otherwise, <value>false</value>. | ||
/// </returns> | ||
public static bool Contains(this IPAddress ipAddress, IPAddress other) => throw new NotImplementedException(); | ||
|
||
/// <summary> | ||
/// Determines whether an <see cref="NpgsqlInet"/> contains another <see cref="NpgsqlInet"/>. | ||
/// </summary> | ||
/// <param name="inet">The inet to search.</param> | ||
/// <param name="other">The inet to locate.</param> | ||
/// <returns> | ||
/// <value>true</value> if the <see cref="NpgsqlInet"/> contains the other <see cref="NpgsqlInet"/>; otherwise, <value>false</value>. | ||
/// </returns> | ||
public static bool Contains(this NpgsqlInet inet, NpgsqlInet other) => throw new NotImplementedException(); | ||
|
||
/// <summary> | ||
/// Determines whether an <see cref="IPAddress"/> contains or is equal to another <see cref="IPAddress"/>. | ||
/// </summary> | ||
/// <param name="ipAddress">The IP address to search.</param> | ||
/// <param name="other">The IP address to locate.</param> | ||
/// <returns> | ||
/// <value>true</value> if the <see cref="IPAddress"/> contains or is equal to the other <see cref="IPAddress"/>; otherwise, <value>false</value>. | ||
/// </returns> | ||
public static bool ContainsOrEquals(this IPAddress ipAddress, IPAddress other) => throw new NotImplementedException(); | ||
|
||
/// <summary> | ||
/// Determines whether an <see cref="NpgsqlInet"/> contains or is equal to another <see cref="NpgsqlInet"/>. | ||
/// </summary> | ||
/// <param name="inet">The inet to search.</param> | ||
/// <param name="other">The inet to locate.</param> | ||
/// <returns> | ||
/// <value>true</value> if the <see cref="NpgsqlInet"/> contains or is equal to the other <see cref="NpgsqlInet"/>; otherwise, <value>false</value>. | ||
/// </returns> | ||
public static bool ContainsOrEquals(this NpgsqlInet inet, NpgsqlInet other) => throw new NotImplementedException(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
115 changes: 115 additions & 0 deletions
115
src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlNetworkAddressTranslator.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
#region License | ||
|
||
// The PostgreSQL License | ||
// | ||
// Copyright (C) 2016 The Npgsql Development Team | ||
// | ||
// Permission to use, copy, modify, and distribute this software and its | ||
// documentation for any purpose, without fee, and without a written | ||
// agreement is hereby granted, provided that the above copyright notice | ||
// and this paragraph and the following two paragraphs appear in all copies. | ||
// | ||
// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY | ||
// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, | ||
// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS | ||
// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF | ||
// THE POSSIBILITY OF SUCH DAMAGE. | ||
// | ||
// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES, | ||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | ||
// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS | ||
// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS | ||
// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | ||
|
||
#endregion | ||
|
||
using System; | ||
using System.Linq.Expressions; | ||
using JetBrains.Annotations; | ||
using Microsoft.EntityFrameworkCore.Query.ExpressionTranslators; | ||
using Npgsql.EntityFrameworkCore.PostgreSQL.Query.Expressions.Internal; | ||
|
||
namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query.ExpressionTranslators.Internal | ||
{ | ||
/// <summary> | ||
/// Provides translation services for PostgreSQL network address (inet, cidr) operators. | ||
/// </summary> | ||
/// <remarks> | ||
/// See: https://www.postgresql.org/docs/current/static/functions-net.html | ||
/// </remarks> | ||
public class NpgsqlNetworkAddressTranslator : IMethodCallTranslator | ||
{ | ||
/// <inheritdoc /> | ||
[CanBeNull] | ||
public Expression Translate(MethodCallExpression methodCallExpression) => | ||
TryTranslateOperator(methodCallExpression); | ||
|
||
/// <summary> | ||
/// Attempts to translate the <see cref="MethodCallExpression"/> as a PostgreSQL network address operator. | ||
/// </summary> | ||
/// <param name="expression">The <see cref="MethodCallExpression"/> to be translated.</param> | ||
/// <returns> | ||
/// The expression if successful; otherwise, null. | ||
/// </returns> | ||
[CanBeNull] | ||
static Expression TryTranslateOperator([NotNull] MethodCallExpression expression) | ||
{ | ||
switch (expression.Method.Name) | ||
{ | ||
case nameof(NpgsqlNetworkAddressExtensions.Contains): | ||
return MakeBinaryExpression(expression, ">>", typeof(bool)); | ||
|
||
case nameof(NpgsqlNetworkAddressExtensions.ContainsOrEquals): | ||
return MakeBinaryExpression(expression, ">>=", typeof(bool)); | ||
|
||
// case nameof(NpgsqlNetworkAddressExtensions.Overlaps): | ||
// return MakeBinaryExpression(expression, "&&", typeof(bool)); | ||
// | ||
// case nameof(NpgsqlNetworkAddressExtensions.IsStrictlyLeftOf): | ||
// return MakeBinaryExpression(expression, "<<", typeof(bool)); | ||
// | ||
// case nameof(NpgsqlNetworkAddressExtensions.IsStrictlyRightOf): | ||
// return MakeBinaryExpression(expression, ">>", typeof(bool)); | ||
// | ||
// case nameof(NpgsqlNetworkAddressExtensions.DoesNotExtendRightOf): | ||
// return MakeBinaryExpression(expression, "&<", typeof(bool)); | ||
// | ||
// case nameof(NpgsqlNetworkAddressExtensions.DoesNotExtendLeftOf): | ||
// return MakeBinaryExpression(expression, "&>", typeof(bool)); | ||
// | ||
// case nameof(NpgsqlNetworkAddressExtensions.IsAdjacentTo): | ||
// return MakeBinaryExpression(expression, "-|-", typeof(bool)); | ||
|
||
default: | ||
return null; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Constructs a <see cref="CustomBinaryExpression"/>. | ||
/// </summary> | ||
/// <param name="expression">The <see cref="MethodCallExpression"/> containing two parameters.</param> | ||
/// <param name="symbol">The symbolic operator for PostgreSQL.</param> | ||
/// <param name="returnType">The return type of the operator.</param> | ||
/// <returns> | ||
/// A <see cref="CustomBinaryExpression"/>. | ||
/// </returns> | ||
[NotNull] | ||
static Expression MakeBinaryExpression([NotNull] MethodCallExpression expression, [NotNull] string symbol, [NotNull] Type returnType) => | ||
new CustomBinaryExpression(expression.Arguments[0], expression.Arguments[1], symbol, returnType); | ||
|
||
// [NpgsqlBinaryOperator(Symbol = "<", ReturnType = typeof(bool))] LessThan, | ||
// [NpgsqlBinaryOperator(Symbol = "<=", ReturnType = typeof(bool))] LessThanOrEqual, | ||
// [NpgsqlBinaryOperator(Symbol = "=", ReturnType = typeof(bool))] Equal, | ||
// [NpgsqlBinaryOperator(Symbol = ">=", ReturnType = typeof(bool))] GreaterThanOrEqual, | ||
// [NpgsqlBinaryOperator(Symbol = ">", ReturnType = typeof(bool))] GreaterThan, | ||
// [NpgsqlBinaryOperator(Symbol = "<>", ReturnType = typeof(bool))] NotEqual, | ||
// [NpgsqlBinaryOperator(Symbol = "<<", ReturnType = typeof(bool))] ContainedWithin, | ||
// [NpgsqlBinaryOperator(Symbol = "<<=", ReturnType = typeof(bool))] ContainedWithinOrEquals, | ||
// [NpgsqlBinaryOperator(Symbol = "~", ReturnType = typeof(bool))] Not, | ||
// [NpgsqlBinaryOperator(Symbol = "&", ReturnType = typeof(bool))] And, | ||
// [NpgsqlBinaryOperator(Symbol = "|", ReturnType = typeof(bool))] Or, | ||
// [NpgsqlBinaryOperator(Symbol = "+", ReturnType = typeof(bool))] Addition, | ||
// [NpgsqlBinaryOperator(Symbol = "-", ReturnType = typeof(bool))] Subtraction, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
135 changes: 135 additions & 0 deletions
135
test/EFCore.PG.FunctionalTests/Query/NetworkAddressQueryNpgsqlFixture.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
using System; | ||
using System.ComponentModel.DataAnnotations; | ||
using System.ComponentModel.DataAnnotations.Schema; | ||
using System.Net; | ||
using Microsoft.EntityFrameworkCore; | ||
using Microsoft.EntityFrameworkCore.TestUtilities; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Logging; | ||
using Npgsql.EntityFrameworkCore.PostgreSQL.TestUtilities; | ||
using NpgsqlTypes; | ||
|
||
namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query | ||
{ | ||
/// <summary> | ||
/// Represents a fixture suitable for testing network address operators. | ||
/// </summary> | ||
public class NetworkAddressQueryNpgsqlFixture : IDisposable | ||
{ | ||
/// <summary> | ||
/// The <see cref="NpgsqlTestStore"/> used for testing. | ||
/// </summary> | ||
private readonly NpgsqlTestStore _testStore; | ||
|
||
/// <summary> | ||
/// The <see cref="DbContextOptions"/> used for testing. | ||
/// </summary> | ||
private readonly DbContextOptions _options; | ||
|
||
/// <summary> | ||
/// The logger factory used for testing. | ||
/// </summary> | ||
public TestSqlLoggerFactory TestSqlLoggerFactory { get; } | ||
|
||
/// <summary> | ||
/// Initializes a <see cref="NetworkAddressQueryNpgsqlFixture"/>. | ||
/// </summary> | ||
// ReSharper disable once UnusedMember.Global | ||
public NetworkAddressQueryNpgsqlFixture() | ||
{ | ||
TestSqlLoggerFactory = new TestSqlLoggerFactory(); | ||
|
||
_testStore = NpgsqlTestStore.CreateScratch(); | ||
|
||
_options = | ||
new DbContextOptionsBuilder() | ||
.UseNpgsql(_testStore.ConnectionString, b => b.ApplyConfiguration()) | ||
.UseInternalServiceProvider( | ||
new ServiceCollection() | ||
.AddEntityFrameworkNpgsql() | ||
.AddSingleton<ILoggerFactory>(TestSqlLoggerFactory) | ||
.BuildServiceProvider()) | ||
.Options; | ||
|
||
using (NetContext context = CreateContext()) | ||
{ | ||
context.Database.EnsureCreated(); | ||
|
||
context.NetTestEntities | ||
.AddRange( | ||
new NetTestEntity { Id = 1, InetMappedToIPAddress = new IPAddress(1), CidrMappedToNpgsqlInet = new IPAddress(1) }, | ||
new NetTestEntity { Id = 2, InetMappedToIPAddress = new IPAddress(2), CidrMappedToNpgsqlInet = new IPAddress(2) }, | ||
new NetTestEntity { Id = 3, InetMappedToIPAddress = new IPAddress(3), CidrMappedToNpgsqlInet = new IPAddress(3) }, | ||
new NetTestEntity { Id = 4, InetMappedToIPAddress = new IPAddress(4), CidrMappedToNpgsqlInet = new IPAddress(4) }, | ||
new NetTestEntity { Id = 5, InetMappedToIPAddress = new IPAddress(5), CidrMappedToNpgsqlInet = new IPAddress(5) }, | ||
new NetTestEntity { Id = 6, InetMappedToIPAddress = new IPAddress(6), CidrMappedToNpgsqlInet = new IPAddress(6) }, | ||
new NetTestEntity { Id = 7, InetMappedToIPAddress = new IPAddress(7), CidrMappedToNpgsqlInet = new IPAddress(7) }, | ||
new NetTestEntity { Id = 8, InetMappedToIPAddress = new IPAddress(8), CidrMappedToNpgsqlInet = new IPAddress(8) }, | ||
new NetTestEntity { Id = 9, InetMappedToIPAddress = new IPAddress(9), CidrMappedToNpgsqlInet = new IPAddress(9) }, | ||
new NetTestEntity { Id = 10, InetMappedToIPAddress = new IPAddress(10), CidrMappedToNpgsqlInet = new IPAddress(10) }); | ||
|
||
context.SaveChanges(); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Creates a new <see cref="NetContext"/>. | ||
/// </summary> | ||
/// <returns> | ||
/// A <see cref="NetContext"/> for testing. | ||
/// </returns> | ||
public NetContext CreateContext() | ||
{ | ||
return new NetContext(_options); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public void Dispose() | ||
{ | ||
_testStore.Dispose(); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Represents an entity suitable for testing network address operators. | ||
/// </summary> | ||
public class NetTestEntity | ||
{ | ||
/// <summary> | ||
/// The primary key. | ||
/// </summary> | ||
[Key] | ||
public int Id { get; set; } | ||
|
||
/// <summary> | ||
/// The network address. | ||
/// </summary> | ||
[Column(TypeName = "inet")] | ||
public IPAddress InetMappedToIPAddress { get; set; } | ||
|
||
/// <summary> | ||
/// The network address. | ||
/// </summary> | ||
[Column(TypeName = "cidr")] | ||
public NpgsqlInet CidrMappedToNpgsqlInet { get; set; } | ||
} | ||
|
||
/// <summary> | ||
/// Represents a database suitable for testing network address operators. | ||
/// </summary> | ||
public class NetContext : DbContext | ||
{ | ||
/// <summary> | ||
/// Represents a set of entities with <see cref="IPAddress"/> properties. | ||
/// </summary> | ||
public DbSet<NetTestEntity> NetTestEntities { get; set; } | ||
|
||
/// <summary> | ||
/// Initializes a <see cref="NetContext"/>. | ||
/// </summary> | ||
/// <param name="options"> | ||
/// The options to be used for configuration. | ||
/// </param> | ||
public NetContext(DbContextOptions options) : base(options) { } | ||
} | ||
} |
Oops, something went wrong.