From b02bff36e45d01246ba4c72a17cdbe90ac0ce64d Mon Sep 17 00:00:00 2001 From: Austin Drenski Date: Thu, 24 May 2018 13:36:37 -0400 Subject: [PATCH] Retargeting cidr from NpgsqlInet to (IPAddress Address, int Subnet). - Updates: - Completed NpgsqlNetworkAddressTranslator switch. - Completed NpgsqlNetworkAddressExtensions for inet-inet and cidr-cidr. - Added ClientEvaluationNotSupportedException to throw from provider-specific extension methods. - TODO: - Add non-operators for inet and cidr (i.e. functions). - Problems: - Adding entities that have a tuple throws an exception related to a binary equality operator? --- .../NpgsqlNetworkAddressExtensions.cs | 485 ++++++++++++++++++ .../Extensions/NpgsqlRangeExtensions.cs | 70 +-- .../NpgsqlNetworkAddressExtensions.cs | 95 ---- .../NpgsqlNetworkAddressTranslator.cs | 62 ++- .../Mapping/NpgsqlNetworkTypeMappings.cs | 48 +- .../Internal/NpgsqlTypeMappingSource.cs | 77 ++- .../ClientEvaluationNotSupportedException.cs | 48 ++ .../Query/NetworkAddressQueryNpgsqlTest.cs | 114 ++-- 8 files changed, 741 insertions(+), 258 deletions(-) create mode 100644 src/EFCore.PG/Extensions/NpgsqlNetworkAddressExtensions.cs delete mode 100644 src/EFCore.PG/NpgsqlNetworkAddressExtensions.cs create mode 100644 src/EFCore.PG/Utilities/ClientEvaluationNotSupportedException.cs diff --git a/src/EFCore.PG/Extensions/NpgsqlNetworkAddressExtensions.cs b/src/EFCore.PG/Extensions/NpgsqlNetworkAddressExtensions.cs new file mode 100644 index 0000000000..5560a9af68 --- /dev/null +++ b/src/EFCore.PG/Extensions/NpgsqlNetworkAddressExtensions.cs @@ -0,0 +1,485 @@ +#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.Net; +using JetBrains.Annotations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities; + +// ReSharper disable once CheckNamespace +namespace Microsoft.EntityFrameworkCore +{ + /// + /// Provides extension methods supporting PostgreSQL network address operator translation. + /// + [PublicAPI] + public static class NpgsqlNetworkAddressExtensions + { + /// + /// Determines whether an contains another . + /// + /// The instance. + /// The IP address to search. + /// The IP address to locate. + /// + /// True if the contains the other ; otherwise, false. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static bool Contains([CanBeNull] this DbFunctions _, IPAddress ipAddress, IPAddress other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Determines whether an (IPAddress Address, int Subnet) contains another (IPAddress Address, int Subnet). + /// + /// The instance. + /// The cidr to search. + /// The cidr to locate. + /// + /// True if the (IPAddress Address, int Subnet) contains the other (IPAddress Address, int Subnet); otherwise, false. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static bool Contains([CanBeNull] this DbFunctions _, (IPAddress Address, int Subnet) cidr, (IPAddress Address, int Subnet) other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Determines whether an contains or is equal to another . + /// + /// The instance. + /// The IP address to search. + /// The IP address to locate. + /// + /// True if the contains or is equal to the other ; otherwise, false. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static bool ContainsOrEqual([CanBeNull] this DbFunctions _, IPAddress ipAddress, IPAddress other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Determines whether an (IPAddress Address, int Subnet) contains or is equal to another (IPAddress Address, int Subnet). + /// + /// The instance. + /// The cidr to search. + /// The cidr to locate. + /// + /// True if the (IPAddress Address, int Subnet) contains or is equal to the other (IPAddress Address, int Subnet); otherwise, false. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static bool ContainsOrEqual([CanBeNull] this DbFunctions _, (IPAddress Address, int Subnet) cidr, (IPAddress Address, int Subnet) other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Determines whether an is less than another . + /// + /// The instance. + /// The left-hand inet. + /// The right-hand inet. + /// + /// True if the is less than the other ; otherwise, false. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static bool LessThan([CanBeNull] this DbFunctions _, IPAddress inet, IPAddress other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Determines whether an (IPAddress Address, int Subnet) is less than another (IPAddress Address, int Subnet). + /// + /// The instance. + /// The left-hand cidr. + /// The right-hand cidr. + /// + /// True if the (IPAddress Address, int Subnet) is less than the other (IPAddress Address, int Subnet); otherwise, false. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static bool LessThan([CanBeNull] this DbFunctions _, (IPAddress Address, int Subnet) cidr, (IPAddress Address, int Subnet) other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Determines whether an is less than or equal to another . + /// + /// The instance. + /// The left-hand inet. + /// The right-hand inet. + /// + /// True if the is less than or equal to the other ; otherwise, false. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static bool LessThanOrEqual([CanBeNull] this DbFunctions _, IPAddress inet, IPAddress other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Determines whether an (IPAddress Address, int Subnet) is less than or equal to another (IPAddress Address, int Subnet). + /// + /// The instance. + /// The left-hand cidr. + /// The right-hand cidr. + /// + /// True if the (IPAddress Address, int Subnet) is less than or equal to the other (IPAddress Address, int Subnet); otherwise, false. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static bool LessThanOrEqual([CanBeNull] this DbFunctions _, (IPAddress Address, int Subnet) cidr, (IPAddress Address, int Subnet) other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Determines whether an is equal to another . + /// + /// The instance. + /// The left-hand inet. + /// The right-hand inet. + /// + /// True if the is equal to the other ; otherwise, false. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static bool Equal([CanBeNull] this DbFunctions _, IPAddress inet, IPAddress other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Determines whether an (IPAddress Address, int Subnet) is equal to another (IPAddress Address, int Subnet). + /// + /// The instance. + /// The left-hand cidr. + /// The right-hand cidr. + /// + /// True if the (IPAddress Address, int Subnet) is equal to the other (IPAddress Address, int Subnet); otherwise, false. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static bool Equal([CanBeNull] this DbFunctions _, (IPAddress Address, int Subnet) cidr, (IPAddress Address, int Subnet) other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Determines whether an is greater than or equal to another . + /// + /// The instance. + /// The left-hand inet. + /// The right-hand inet. + /// + /// True if the is greater than or equal to the other ; otherwise, false. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static bool GreaterThanOrEqual([CanBeNull] this DbFunctions _, IPAddress inet, IPAddress other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Determines whether an (IPAddress Address, int Subnet) is greater than or equal to another (IPAddress Address, int Subnet). + /// + /// The instance. + /// The left-hand cidr. + /// The right-hand cidr. + /// + /// True if the (IPAddress Address, int Subnet) is greater than or equal to the other (IPAddress Address, int Subnet); otherwise, false. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static bool GreaterThanOrEqual([CanBeNull] this DbFunctions _, (IPAddress Address, int Subnet) cidr, (IPAddress Address, int Subnet) other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Determines whether an is greater than another . + /// + /// The instance. + /// The left-hand inet. + /// The right-hand inet. + /// + /// True if the is greater than the other ; otherwise, false. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static bool GreaterThan([CanBeNull] this DbFunctions _, IPAddress inet, IPAddress other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Determines whether an (IPAddress Address, int Subnet) is greater than another (IPAddress Address, int Subnet). + /// + /// The instance. + /// The left-hand cidr. + /// The right-hand cidr. + /// + /// True if the (IPAddress Address, int Subnet) is greater than the other (IPAddress Address, int Subnet); otherwise, false. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static bool GreaterThan([CanBeNull] this DbFunctions _, (IPAddress Address, int Subnet) cidr, (IPAddress Address, int Subnet) other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Determines whether an is not equal to another . + /// + /// The instance. + /// The left-hand inet. + /// The right-hand inet. + /// + /// True if the is not equal to the other ; otherwise, false. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static bool NotEqual([CanBeNull] this DbFunctions _, IPAddress inet, IPAddress other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Determines whether an (IPAddress Address, int Subnet) is not equal to another (IPAddress Address, int Subnet). + /// + /// The instance. + /// The left-hand cidr. + /// The right-hand cidr. + /// + /// True if the IPAddress Address, int Subnet) is not equal to the other (IPAddress Address, int Subnet); otherwise, false. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static bool NotEqual([CanBeNull] this DbFunctions _, (IPAddress Address, int Subnet) cidr, (IPAddress Address, int Subnet) other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Determines whether an is contained within another . + /// + /// The instance. + /// The inet to locate. + /// The inet to search. + /// + /// True if the is contained within the other ; otherwise, false. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static bool ContainedBy([CanBeNull] this DbFunctions _, IPAddress inet, IPAddress other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Determines whether an (IPAddress Address, int Subnet) is contained within another (IPAddress Address, int Subnet). + /// + /// The instance. + /// The cidr to locate. + /// The cidr to search. + /// + /// True if the (IPAddress Address, int Subnet) is contained within the other (IPAddress Address, int Subnet); otherwise, false. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static bool ContainedBy([CanBeNull] this DbFunctions _, (IPAddress Address, int Subnet) cidr, (IPAddress Address, int Subnet) other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Determines whether an is contained within or equal to another . + /// + /// The instance. + /// The inet to locate. + /// The inet to search. + /// + /// True if the is contained within or equal to the other ; otherwise, false. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static bool ContainedByOrEqual([CanBeNull] this DbFunctions _, IPAddress inet, IPAddress other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Determines whether an (IPAddress Address, int Subnet) is contained within or equal to another (IPAddress Address, int Subnet). + /// + /// The instance. + /// The cidr to locate. + /// The cidr to search. + /// + /// True if the (IPAddress Address, int Subnet) is contained within or equal to the other (IPAddress Address, int Subnet); otherwise, false. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static bool ContainedByOrEqual([CanBeNull] this DbFunctions _, (IPAddress Address, int Subnet) cidr, (IPAddress Address, int Subnet) other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Computes the bitwise NOT operation on an . + /// + /// The instance. + /// The inet to negate. + /// + /// The result of the bitwise NOT operation. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static IPAddress Not([CanBeNull] this DbFunctions _, IPAddress inet) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Computes the bitwise NOT operation on an (IPAddress Address, int Subnet). + /// + /// The instance. + /// The cidr to negate. + /// + /// The result of the bitwise NOT operation. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static (IPAddress Address, int Subnet) Not([CanBeNull] this DbFunctions _, (IPAddress Address, int Subnet) cidr) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Computes the bitwise AND of two instances. + /// + /// The instance. + /// The left-hand inet. + /// The right-hand inet. + /// + /// The result of the bitwise AND operation. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static IPAddress And([CanBeNull] this DbFunctions _, IPAddress inet, IPAddress other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Computes the bitwise AND of two (IPAddress Address, int Subnet) instances. + /// + /// The instance. + /// The left-hand cidr. + /// The right-hand cidr. + /// + /// The result of the bitwise AND operation. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static (IPAddress Address, int Subnet) And([CanBeNull] this DbFunctions _, (IPAddress Address, int Subnet) cidr, (IPAddress Address, int Subnet) other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Computes the bitwise OR of two instances. + /// + /// The instance. + /// The left-hand inet. + /// The right-hand inet. + /// + /// The result of the bitwise OR operation. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static IPAddress Or([CanBeNull] this DbFunctions _, IPAddress inet, IPAddress other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Computes the bitwise OR of two (IPAddress Address, int Subnet) instances. + /// + /// The instance. + /// The left-hand cidr. + /// The right-hand cidr. + /// + /// The result of the bitwise OR operation. + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static (IPAddress Address, int Subnet) Or([CanBeNull] this DbFunctions _, (IPAddress Address, int Subnet) cidr, (IPAddress Address, int Subnet) other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Adds the to the . + /// + /// The instance. + /// The inet. + /// The value to add. + /// + /// The augmented by the . + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static IPAddress Add([CanBeNull] this DbFunctions _, IPAddress inet, int value) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Adds the to the (IPAddress Address, int Subnet). + /// + /// The instance. + /// The cidr. + /// The value to add. + /// + /// The (IPAddress Address, int Subnet) augmented by the . + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static (IPAddress Address, int Subnet) Add([CanBeNull] this DbFunctions _, (IPAddress Address, int Subnet) cidr, int value) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Subtracts the from the . + /// + /// The instance. + /// The inet. + /// The value to subtract. + /// + /// The augmented by the . + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static IPAddress Subtract([CanBeNull] this DbFunctions _, IPAddress inet, int value) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Subtracts the from the (IPAddress Address, int Subnet). + /// + /// The instance. + /// The inet. + /// The value to subtract. + /// + /// The (IPAddress Address, int Subnet) augmented by the . + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static (IPAddress Address, int Subnet) Subtract([CanBeNull] this DbFunctions _, (IPAddress Address, int Subnet) cidr, int value) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Subtracts one from another . + /// + /// The instance. + /// The inet from which to subtract. + /// The inet to subtract. + /// + /// The augmented by the . + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static IPAddress Subtract([CanBeNull] this DbFunctions _, IPAddress inet, IPAddress other) => throw new ClientEvaluationNotSupportedException(); + + /// + /// Subtracts one (IPAddress Address, int Subnet) from another (IPAddress Address, int Subnet). + /// + /// The instance. + /// The cidr from which to subtract. + /// The cidr to subtract. + /// + /// The (IPAddress Address, int Subnet) augmented by the . + /// + /// + /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. + /// + public static (IPAddress Address, int Subnet) Subtract([CanBeNull] this DbFunctions _, (IPAddress Address, int Subnet) cidr, (IPAddress Address, int Subnet) other) => throw new ClientEvaluationNotSupportedException(); + } +} diff --git a/src/EFCore.PG/Extensions/NpgsqlRangeExtensions.cs b/src/EFCore.PG/Extensions/NpgsqlRangeExtensions.cs index 3bdf2688af..5dab8880eb 100644 --- a/src/EFCore.PG/Extensions/NpgsqlRangeExtensions.cs +++ b/src/EFCore.PG/Extensions/NpgsqlRangeExtensions.cs @@ -23,7 +23,8 @@ #endregion -using System; +using JetBrains.Annotations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities; using NpgsqlTypes; // ReSharper disable once CheckNamespace @@ -32,6 +33,7 @@ namespace Microsoft.EntityFrameworkCore /// /// Provides extension methods for supporting PostgreSQL translation. /// + [PublicAPI] public static class NpgsqlRangeExtensions { /// @@ -41,12 +43,12 @@ public static class NpgsqlRangeExtensions /// The value to locate in the range. /// The type of the elements of . /// - /// true if the range contains the specified value; otherwise, false. + /// True if the range contains the specified value; otherwise, false. /// - /// + /// /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. /// - public static bool Contains(this NpgsqlRange range, T value) where T : IComparable => throw new NotSupportedException(); + public static bool Contains(this NpgsqlRange range, T value) => throw new ClientEvaluationNotSupportedException(); /// /// Determines whether a range contains a specified range. @@ -55,12 +57,12 @@ public static class NpgsqlRangeExtensions /// The specified range to locate in the range. /// The type of the elements of . /// - /// true if the range contains the specified range; otherwise, false. + /// True if the range contains the specified range; otherwise, false. /// - /// + /// /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. /// - public static bool Contains(this NpgsqlRange a, NpgsqlRange b) where T : IComparable => throw new NotSupportedException(); + public static bool Contains(this NpgsqlRange a, NpgsqlRange b) => throw new ClientEvaluationNotSupportedException(); /// /// Determines whether a range is contained by a specified range. @@ -69,12 +71,12 @@ public static class NpgsqlRangeExtensions /// The range in which to locate the specified range. /// The type of the elements of . /// - /// true if the range contains the specified range; otherwise, false. + /// True if the range contains the specified range; otherwise, false. /// - /// + /// /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. /// - public static bool ContainedBy(this NpgsqlRange a, NpgsqlRange b) where T : IComparable => b.Contains(a); + public static bool ContainedBy(this NpgsqlRange a, NpgsqlRange b) => throw new ClientEvaluationNotSupportedException(); /// /// Determines whether a range overlaps another range. @@ -83,12 +85,12 @@ public static class NpgsqlRangeExtensions /// The second range. /// The type of the elements of . /// - /// true if the ranges overlap (share points in common); otherwise, false. + /// True if the ranges overlap (share points in common); otherwise, false. /// - /// + /// /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. /// - public static bool Overlaps(this NpgsqlRange a, NpgsqlRange b) where T : IComparable => throw new NotSupportedException(); + public static bool Overlaps(this NpgsqlRange a, NpgsqlRange b) => throw new ClientEvaluationNotSupportedException(); /// /// Determines whether a range is strictly to the left of another range. @@ -97,12 +99,12 @@ public static class NpgsqlRangeExtensions /// The second range. /// The type of the elements of . /// - /// true if the first range is strictly to the left of the second; otherwise, false. + /// True if the first range is strictly to the left of the second; otherwise, false. /// - /// + /// /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. /// - public static bool IsStrictlyLeftOf(this NpgsqlRange a, NpgsqlRange b) where T : IComparable => throw new NotSupportedException(); + public static bool IsStrictlyLeftOf(this NpgsqlRange a, NpgsqlRange b) => throw new ClientEvaluationNotSupportedException(); /// /// Determines whether a range is strictly to the right of another range. @@ -111,12 +113,12 @@ public static class NpgsqlRangeExtensions /// The second range. /// The type of the elements of . /// - /// true if the first range is strictly to the right of the second; otherwise, false. + /// True if the first range is strictly to the right of the second; otherwise, false. /// - /// + /// /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. /// - public static bool IsStrictlyRightOf(this NpgsqlRange a, NpgsqlRange b) where T : IComparable => throw new NotSupportedException(); + public static bool IsStrictlyRightOf(this NpgsqlRange a, NpgsqlRange b) => throw new ClientEvaluationNotSupportedException(); /// /// Determines whether a range does not extend to the left of another range. @@ -125,12 +127,12 @@ public static class NpgsqlRangeExtensions /// The second range. /// The type of the elements of . /// - /// true if the first range does not extend to the left of the second; otherwise, false. + /// True if the first range does not extend to the left of the second; otherwise, false. /// - /// + /// /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. /// - public static bool DoesNotExtendLeftOf(this NpgsqlRange a, NpgsqlRange b) where T : IComparable => throw new NotSupportedException(); + public static bool DoesNotExtendLeftOf(this NpgsqlRange a, NpgsqlRange b) => throw new ClientEvaluationNotSupportedException(); /// /// Determines whether a range does not extend to the right of another range. @@ -139,12 +141,12 @@ public static class NpgsqlRangeExtensions /// The second range. /// The type of the elements of . /// - /// true if the first range does not extend to the right of the second; otherwise, false. + /// True if the first range does not extend to the right of the second; otherwise, false. /// - /// + /// /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. /// - public static bool DoesNotExtendRightOf(this NpgsqlRange a, NpgsqlRange b) where T : IComparable => throw new NotSupportedException(); + public static bool DoesNotExtendRightOf(this NpgsqlRange a, NpgsqlRange b) => throw new ClientEvaluationNotSupportedException(); /// /// Determines whether a range is adjacent to another range. @@ -153,12 +155,12 @@ public static class NpgsqlRangeExtensions /// The second range. /// The type of the elements of . /// - /// true if the ranges are adjacent; otherwise, false. + /// True if the ranges are adjacent; otherwise, false. /// - /// + /// /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. /// - public static bool IsAdjacentTo(this NpgsqlRange a, NpgsqlRange b) where T : IComparable => throw new NotSupportedException(); + public static bool IsAdjacentTo(this NpgsqlRange a, NpgsqlRange b) => throw new ClientEvaluationNotSupportedException(); /// /// Returns the set union, which means unique elements that appear in either of two ranges. @@ -169,10 +171,10 @@ public static class NpgsqlRangeExtensions /// /// The unique elements that appear in either range. /// - /// + /// /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. /// - public static NpgsqlRange Union(this NpgsqlRange a, NpgsqlRange b) where T : IComparable => throw new NotSupportedException(); + public static NpgsqlRange Union(this NpgsqlRange a, NpgsqlRange b) => throw new ClientEvaluationNotSupportedException(); /// /// Returns the set intersection, which means elements that appear in each of two ranges. @@ -183,10 +185,10 @@ public static class NpgsqlRangeExtensions /// /// The elements that appear in both ranges. /// - /// + /// /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. /// - public static NpgsqlRange Intersect(this NpgsqlRange a, NpgsqlRange b) where T : IComparable => throw new NotSupportedException(); + public static NpgsqlRange Intersect(this NpgsqlRange a, NpgsqlRange b) => throw new ClientEvaluationNotSupportedException(); /// /// Returns the set difference, which means the elements of one range that do not appear in a second range. @@ -197,9 +199,9 @@ public static class NpgsqlRangeExtensions /// /// The elements that appear in the first range, but not the second range. /// - /// + /// /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. /// - public static NpgsqlRange Except(this NpgsqlRange a, NpgsqlRange b) where T : IComparable => throw new NotSupportedException(); + public static NpgsqlRange Except(this NpgsqlRange a, NpgsqlRange b) => throw new ClientEvaluationNotSupportedException(); } } diff --git a/src/EFCore.PG/NpgsqlNetworkAddressExtensions.cs b/src/EFCore.PG/NpgsqlNetworkAddressExtensions.cs deleted file mode 100644 index 12ae0cef23..0000000000 --- a/src/EFCore.PG/NpgsqlNetworkAddressExtensions.cs +++ /dev/null @@ -1,95 +0,0 @@ -#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 JetBrains.Annotations; -using NpgsqlTypes; - -// ReSharper disable once CheckNamespace -namespace Microsoft.EntityFrameworkCore -{ - /// - /// Provides extension methods supporting PostgreSQL network address operator translation. - /// - public static class NpgsqlNetworkAddressExtensions - { - /// - /// Determines whether an contains another . - /// - /// The DbFunctions instance. - /// The IP address to search. - /// The IP address to locate. - /// - /// true if the contains the other ; otherwise, false. - /// - /// - /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. - /// - public static bool Contains([CanBeNull] this DbFunctions _, [CanBeNull] IPAddress ipAddress, [CanBeNull] IPAddress other) => throw new NotSupportedException(); - - /// - /// Determines whether an contains another . - /// - /// The DbFunctions instance. - /// The inet to search. - /// The inet to locate. - /// - /// true if the contains the other ; otherwise, false. - /// - /// - /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. - /// - public static bool Contains([CanBeNull] this DbFunctions _, NpgsqlInet inet, NpgsqlInet other) => throw new NotSupportedException(); - - /// - /// Determines whether an contains or is equal to another . - /// - /// The DbFunctions instance. - /// The IP address to search. - /// The IP address to locate. - /// - /// true if the contains or is equal to the other ; otherwise, false. - /// - /// - /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. - /// - public static bool ContainsOrEquals([CanBeNull] this DbFunctions _, [CanBeNull] IPAddress ipAddress, [CanBeNull] IPAddress other) => throw new NotSupportedException(); - - /// - /// Determines whether an contains or is equal to another . - /// - /// The DbFunctions instance. - /// The inet to search. - /// The inet to locate. - /// - /// true if the contains or is equal to the other ; otherwise, false. - /// - /// - /// This method is only intended for use via SQL translation as part of an EF Core LINQ query. - /// - public static bool ContainsOrEquals([CanBeNull] this DbFunctions _, NpgsqlInet inet, NpgsqlInet other) => throw new NotSupportedException(); - } -} diff --git a/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlNetworkAddressTranslator.cs b/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlNetworkAddressTranslator.cs index 9fea7fbbb4..2348539761 100644 --- a/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlNetworkAddressTranslator.cs +++ b/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlNetworkAddressTranslator.cs @@ -25,6 +25,7 @@ using System.Linq.Expressions; using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Query.ExpressionTranslators; using Npgsql.EntityFrameworkCore.PostgreSQL.Query.Expressions.Internal; @@ -42,30 +43,59 @@ public class NpgsqlNetworkAddressTranslator : IMethodCallTranslator [CanBeNull] public Expression Translate(MethodCallExpression expression) { + if (expression.Method.DeclaringType != typeof(NpgsqlNetworkAddressExtensions)) + return null; + switch (expression.Method.Name) { case nameof(NpgsqlNetworkAddressExtensions.Contains): - return new CustomBinaryExpression(expression.Arguments[0], expression.Arguments[1], ">>", typeof(bool)); + return new CustomBinaryExpression(expression.Arguments[1], expression.Arguments[2], ">>", typeof(bool)); + + case nameof(NpgsqlNetworkAddressExtensions.ContainsOrEqual): + return new CustomBinaryExpression(expression.Arguments[1], expression.Arguments[2], ">>=", typeof(bool)); + + case nameof(NpgsqlNetworkAddressExtensions.LessThan): + return new CustomBinaryExpression(expression.Arguments[1], expression.Arguments[2], "<", typeof(bool)); + + case nameof(NpgsqlNetworkAddressExtensions.LessThanOrEqual): + return new CustomBinaryExpression(expression.Arguments[1], expression.Arguments[2], "<=", typeof(bool)); + + case nameof(NpgsqlNetworkAddressExtensions.Equal): + return new CustomBinaryExpression(expression.Arguments[1], expression.Arguments[2], "=", typeof(bool)); + + case nameof(NpgsqlNetworkAddressExtensions.GreaterThanOrEqual): + return new CustomBinaryExpression(expression.Arguments[1], expression.Arguments[2], ">=", typeof(bool)); + + case nameof(NpgsqlNetworkAddressExtensions.GreaterThan): + return new CustomBinaryExpression(expression.Arguments[1], expression.Arguments[2], ">", typeof(bool)); + + case nameof(NpgsqlNetworkAddressExtensions.NotEqual): + return new CustomBinaryExpression(expression.Arguments[1], expression.Arguments[2], "<>", typeof(bool)); + + case nameof(NpgsqlNetworkAddressExtensions.ContainedBy): + return new CustomBinaryExpression(expression.Arguments[1], expression.Arguments[2], "<<", typeof(bool)); + + case nameof(NpgsqlNetworkAddressExtensions.ContainedByOrEqual): + return new CustomBinaryExpression(expression.Arguments[1], expression.Arguments[2], "<<=", typeof(bool)); + + case nameof(NpgsqlNetworkAddressExtensions.Not): + return new CustomUnaryExpression(expression.Arguments[1], "~", expression.Arguments[1].Type); + + case nameof(NpgsqlNetworkAddressExtensions.And): + return new CustomBinaryExpression(expression.Arguments[1], expression.Arguments[2], "&", expression.Arguments[1].Type); + + case nameof(NpgsqlNetworkAddressExtensions.Or): + return new CustomBinaryExpression(expression.Arguments[1], expression.Arguments[2], "|", expression.Arguments[1].Type); + + case nameof(NpgsqlNetworkAddressExtensions.Add): + return new CustomBinaryExpression(expression.Arguments[1], expression.Arguments[2], "+", expression.Arguments[1].Type); - case nameof(NpgsqlNetworkAddressExtensions.ContainsOrEquals): - return new CustomBinaryExpression(expression.Arguments[0], expression.Arguments[1], ">>=", typeof(bool)); + case nameof(NpgsqlNetworkAddressExtensions.Subtract): + return new CustomBinaryExpression(expression.Arguments[1], expression.Arguments[2], "-", expression.Arguments[1].Type); default: return null; } } -// [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, } } diff --git a/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlNetworkTypeMappings.cs b/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlNetworkTypeMappings.cs index 7ea53b6a9d..6d92211ec8 100644 --- a/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlNetworkTypeMappings.cs +++ b/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlNetworkTypeMappings.cs @@ -1,8 +1,30 @@ -using System; -using System.Collections.Generic; +#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.Net; using System.Net.NetworkInformation; -using System.Text; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using NpgsqlTypes; @@ -11,10 +33,10 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping { public class NpgsqlMacaddrTypeMapping : NpgsqlTypeMapping { - public NpgsqlMacaddrTypeMapping() : base("macaddr", typeof(PhysicalAddress), NpgsqlDbType.MacAddr) {} + public NpgsqlMacaddrTypeMapping() : base("macaddr", typeof(PhysicalAddress), NpgsqlDbType.MacAddr) { } protected NpgsqlMacaddrTypeMapping(RelationalTypeMappingParameters parameters, NpgsqlDbType npgsqlDbType) - : base(parameters, npgsqlDbType) {} + : base(parameters, npgsqlDbType) { } public override RelationalTypeMapping Clone(string storeType, int? size) => new NpgsqlMacaddrTypeMapping(Parameters.WithStoreTypeAndSize(storeType, size), NpgsqlDbType); @@ -28,10 +50,10 @@ protected override string GenerateNonNullSqlLiteral(object value) public class NpgsqlMacaddr8TypeMapping : NpgsqlTypeMapping { - public NpgsqlMacaddr8TypeMapping() : base("macaddr8", typeof(PhysicalAddress), NpgsqlDbType.MacAddr) {} + public NpgsqlMacaddr8TypeMapping() : base("macaddr8", typeof(PhysicalAddress), NpgsqlDbType.MacAddr) { } protected NpgsqlMacaddr8TypeMapping(RelationalTypeMappingParameters parameters, NpgsqlDbType npgsqlDbType) - : base(parameters, npgsqlDbType) {} + : base(parameters, npgsqlDbType) { } public override RelationalTypeMapping Clone(string storeType, int? size) => new NpgsqlMacaddr8TypeMapping(Parameters.WithStoreTypeAndSize(storeType, size), NpgsqlDbType); @@ -45,10 +67,10 @@ protected override string GenerateNonNullSqlLiteral(object value) public class NpgsqlInetTypeMapping : NpgsqlTypeMapping { - public NpgsqlInetTypeMapping() : base("inet", typeof(IPAddress), NpgsqlDbType.Inet) {} + public NpgsqlInetTypeMapping() : base("inet", typeof(IPAddress), NpgsqlDbType.Inet) { } protected NpgsqlInetTypeMapping(RelationalTypeMappingParameters parameters, NpgsqlDbType npgsqlDbType) - : base(parameters, npgsqlDbType) {} + : base(parameters, npgsqlDbType) { } public override RelationalTypeMapping Clone(string storeType, int? size) => new NpgsqlInetTypeMapping(Parameters.WithStoreTypeAndSize(storeType, size), NpgsqlDbType); @@ -62,10 +84,10 @@ protected override string GenerateNonNullSqlLiteral(object value) public class NpgsqlCidrTypeMapping : NpgsqlTypeMapping { - public NpgsqlCidrTypeMapping() : base("cidr", typeof((IPAddress, int)), NpgsqlDbType.Cidr) {} + public NpgsqlCidrTypeMapping() : base("cidr", typeof((IPAddress, int)), NpgsqlDbType.Cidr) { } protected NpgsqlCidrTypeMapping(RelationalTypeMappingParameters parameters, NpgsqlDbType npgsqlDbType) - : base(parameters, npgsqlDbType) {} + : base(parameters, npgsqlDbType) { } public override RelationalTypeMapping Clone(string storeType, int? size) => new NpgsqlCidrTypeMapping(Parameters.WithStoreTypeAndSize(storeType, size), NpgsqlDbType); @@ -75,8 +97,8 @@ public override CoreTypeMapping Clone(ValueConverter converter) protected override string GenerateNonNullSqlLiteral(object value) { - var cidr = ((IPAddress, int))value; - return $"CIDR '{cidr.Item1}/{cidr.Item2}'"; + var cidr = ((IPAddress Address, int Subnet))value; + return $"CIDR '{cidr.Address}/{cidr.Subnet}'"; } } } diff --git a/src/EFCore.PG/Storage/Internal/NpgsqlTypeMappingSource.cs b/src/EFCore.PG/Storage/Internal/NpgsqlTypeMappingSource.cs index 3e7fcd640f..a97e528403 100644 --- a/src/EFCore.PG/Storage/Internal/NpgsqlTypeMappingSource.cs +++ b/src/EFCore.PG/Storage/Internal/NpgsqlTypeMappingSource.cs @@ -30,11 +30,9 @@ using System.Linq; using System.Net; using System.Net.NetworkInformation; -using System.Reflection; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Storage; -using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure; using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal; using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping; using Npgsql.TypeHandlers; @@ -199,41 +197,41 @@ public NpgsqlTypeMappingSource([NotNull] TypeMappingSourceDependencies dependenc var clrTypeMappings = new Dictionary { - { typeof(bool), _bool }, - { typeof(byte[]), _bytea }, - { typeof(float), _float4 }, - { typeof(double), _float8 }, - { typeof(decimal), _numeric }, - { typeof(Guid), _uuid }, - { typeof(byte), _int2Byte }, - { typeof(short), _int2 }, - { typeof(int), _int4 }, - { typeof(long), _int8 }, - { typeof(string), _text }, - { typeof(char), _singleChar }, - { typeof(DateTime), _timestamp }, - { typeof(TimeSpan), _interval }, - { typeof(DateTimeOffset), _timestamptzDto }, - { typeof(PhysicalAddress), _macaddr }, - { typeof(IPAddress), _inet }, - { typeof(NpgsqlInet), _cidr }, - { typeof(BitArray), _varbit }, - { typeof(Dictionary), _hstore }, - { typeof(NpgsqlPoint), _point }, - { typeof(NpgsqlBox), _box }, - { typeof(NpgsqlLine), _line }, - { typeof(NpgsqlLSeg), _lseg }, - { typeof(NpgsqlPath), _path }, - { typeof(NpgsqlPolygon), _polygon }, - { typeof(NpgsqlCircle), _circle }, - - { typeof(NpgsqlRange), _int4range }, - { typeof(NpgsqlRange), _int8range }, - { typeof(NpgsqlRange), _numrange }, - { typeof(NpgsqlRange), _tsrange }, - - { typeof(NpgsqlTsQuery), _tsquery }, - { typeof(NpgsqlTsVector), _tsvector }, + { typeof(bool), _bool }, + { typeof(byte[]), _bytea }, + { typeof(float), _float4 }, + { typeof(double), _float8 }, + { typeof(decimal), _numeric }, + { typeof(Guid), _uuid }, + { typeof(byte), _int2Byte }, + { typeof(short), _int2 }, + { typeof(int), _int4 }, + { typeof(long), _int8 }, + { typeof(string), _text }, + { typeof(char), _singleChar }, + { typeof(DateTime), _timestamp }, + { typeof(TimeSpan), _interval }, + { typeof(DateTimeOffset), _timestamptzDto }, + { typeof(PhysicalAddress), _macaddr }, + { typeof(IPAddress), _inet }, + { typeof((IPAddress, int)), _cidr }, + { typeof(BitArray), _varbit }, + { typeof(Dictionary), _hstore }, + { typeof(NpgsqlPoint), _point }, + { typeof(NpgsqlBox), _box }, + { typeof(NpgsqlLine), _line }, + { typeof(NpgsqlLSeg), _lseg }, + { typeof(NpgsqlPath), _path }, + { typeof(NpgsqlPolygon), _polygon }, + { typeof(NpgsqlCircle), _circle }, + + { typeof(NpgsqlRange), _int4range }, + { typeof(NpgsqlRange), _int8range }, + { typeof(NpgsqlRange), _numrange }, + { typeof(NpgsqlRange), _tsrange }, + + { typeof(NpgsqlTsQuery), _tsquery }, + { typeof(NpgsqlTsVector), _tsvector }, { typeof(NpgsqlTsRankingNormalization), _rankingNormalization } }; @@ -287,10 +285,7 @@ protected override RelationalTypeMapping FindMapping(in RelationalTypeMappingInf // We couldn't find a base (simple) type mapping. Try to find an array. var arrayMapping = FindArrayMapping(mappingInfo); - if (arrayMapping != null) - return arrayMapping; - - return null; + return arrayMapping ?? null; } protected virtual RelationalTypeMapping FindBaseTypeMapping(in RelationalTypeMappingInfo mappingInfo) diff --git a/src/EFCore.PG/Utilities/ClientEvaluationNotSupportedException.cs b/src/EFCore.PG/Utilities/ClientEvaluationNotSupportedException.cs new file mode 100644 index 0000000000..8fce1fdbba --- /dev/null +++ b/src/EFCore.PG/Utilities/ClientEvaluationNotSupportedException.cs @@ -0,0 +1,48 @@ +#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.Runtime.CompilerServices; + +namespace Npgsql.EntityFrameworkCore.PostgreSQL.Utilities +{ + /// + /// The exception that is thrown when a method intended for SQL translation is evaluated by the client. + /// + public class ClientEvaluationNotSupportedException : NotSupportedException + { + readonly string _callerMemberName; + + /// + public override string Message + => $"{_callerMemberName} is only intended for use via SQL translation as part of an EF Core LINQ query."; + + /// + public ClientEvaluationNotSupportedException([CallerMemberName] string method = default) + { + _callerMemberName = method; + } + } +} diff --git a/test/EFCore.PG.FunctionalTests/Query/NetworkAddressQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/NetworkAddressQueryNpgsqlTest.cs index 71543694e3..822aad62fd 100644 --- a/test/EFCore.PG.FunctionalTests/Query/NetworkAddressQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/NetworkAddressQueryNpgsqlTest.cs @@ -1,6 +1,5 @@ using System; using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Net; using Microsoft.EntityFrameworkCore; @@ -8,7 +7,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Npgsql.EntityFrameworkCore.PostgreSQL.TestUtilities; -using NpgsqlTypes; using Xunit; namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query @@ -43,16 +41,16 @@ public void Demonstrate_ValueTypeParametersAreDuplicated() { using (NetContext context = Fixture.CreateContext()) { - NpgsqlInet npgsqlInet = new IPAddress(0); + (IPAddress Address, int Subnet) cidr = (new IPAddress(0), 0); bool[] _ = context.NetTestEntities - .Where(x => EF.Functions.ContainsOrEquals(x.CidrMappedToNpgsqlInet, npgsqlInet)) - .Select(x => x.CidrMappedToNpgsqlInet.Equals(npgsqlInet)) + .Where(x => EF.Functions.ContainsOrEqual(x.Cidr, cidr)) + .Select(x => x.Cidr.Equals(cidr)) .ToArray(); - AssertContainsSql("SELECT x.\"CidrMappedToNpgsqlInet\" = @__npgsqlInet_0"); - AssertContainsSql("WHERE x.\"CidrMappedToNpgsqlInet\" >>= @__npgsqlInet_0"); + AssertContainsSql("SELECT x.\"Cidr\" = @__cidr_1 = TRUE"); + AssertContainsSql("WHERE x.\"Cidr\" >>= @__cidr_1 = TRUE"); } } @@ -60,37 +58,37 @@ public void Demonstrate_ValueTypeParametersAreDuplicated() /// Tests translation for . /// [Fact] - public void IPAddressContainsIPAddress() + public void IPAddress_inet_Contains_inet() { using (NetContext context = Fixture.CreateContext()) { - IPAddress address = new IPAddress(0); + IPAddress inet = new IPAddress(0); NetTestEntity[] _ = context.NetTestEntities - .Where(x => EF.Functions.Contains(x.InetMappedToIPAddress, address)) + .Where(x => EF.Functions.Contains(x.Inet, inet)) .ToArray(); - AssertContainsSql("WHERE x.\"InetMappedToIPAddress\" >> @__address_0"); + AssertContainsSql("WHERE x.\"Inet\" >> @__inet_1 = TRUE"); } } /// - /// Tests translation for . + /// Tests translation for . /// [Fact] - public void NpgsqlInetContainsNpgsqlInet() + public void ValueTuple_cidr_Contains_cidr() { using (NetContext context = Fixture.CreateContext()) { - NpgsqlInet npgsqlInet = new IPAddress(0); + (IPAddress Address, int Subnet) cidr = (new IPAddress(0), 0); NetTestEntity[] _ = context.NetTestEntities - .Where(x => EF.Functions.Contains(x.CidrMappedToNpgsqlInet, npgsqlInet)) + .Where(x => EF.Functions.Contains(x.Cidr, cidr)) .ToArray(); - AssertContainsSql("WHERE x.\"CidrMappedToNpgsqlInet\" >> @__npgsqlInet_0"); + AssertContainsSql("WHERE x.\"Cidr\" >> @__cidr_1 = TRUE"); } } @@ -98,37 +96,37 @@ public void NpgsqlInetContainsNpgsqlInet() /// Tests inverse translation for . /// [Fact] - public void IPAddressDoesNotContainsIPAddress() + public void IPAddress_inet_DoesNotContain_inet() { using (NetContext context = Fixture.CreateContext()) { - IPAddress address = new IPAddress(0); + IPAddress inet = new IPAddress(0); NetTestEntity[] _ = context.NetTestEntities - .Where(x => !EF.Functions.Contains(x.InetMappedToIPAddress, address)) + .Where(x => !EF.Functions.Contains(x.Inet, inet)) .ToArray(); - AssertContainsSql("WHERE NOT (x.\"InetMappedToIPAddress\" >> @__address_0 = TRUE)"); + AssertContainsSql("WHERE NOT (x.\"Inet\" >> @__inet_1 = TRUE)"); } } /// - /// Tests inverse translation for . + /// Tests inverse translation for . /// [Fact] - public void NpgsqlInetDoesNotContainNpgsqlInet() + public void ValueTuple_cidr_DoesNotContain_cidr() { using (NetContext context = Fixture.CreateContext()) { - NpgsqlInet npgsqlInet = new IPAddress(0); + (IPAddress Address, int Subnet) cidr = (new IPAddress(0), 0); NetTestEntity[] _ = context.NetTestEntities - .Where(x => !EF.Functions.Contains(x.CidrMappedToNpgsqlInet, npgsqlInet)) + .Where(x => !EF.Functions.Contains(x.Cidr, cidr)) .ToArray(); - AssertContainsSql("WHERE NOT (x.\"CidrMappedToNpgsqlInet\" >> @__npgsqlInet_0 = TRUE)"); + AssertContainsSql("WHERE NOT (x.\"Cidr\" >> @__cidr_1 = TRUE)"); } } @@ -136,37 +134,37 @@ public void NpgsqlInetDoesNotContainNpgsqlInet() /// Tests translation for . /// [Fact] - public void IPAddressContainOrEqualIPAddress() + public void IPAddress_inet_ContainsOrEquals_inet() { using (NetContext context = Fixture.CreateContext()) { - IPAddress address = new IPAddress(0); + IPAddress inet = new IPAddress(0); NetTestEntity[] _ = context.NetTestEntities - .Where(x => EF.Functions.ContainsOrEquals(x.InetMappedToIPAddress, address)) + .Where(x => EF.Functions.ContainsOrEqual(x.Inet, inet)) .ToArray(); - AssertContainsSql("WHERE x.\"InetMappedToIPAddress\" >>= @__address_0"); + AssertContainsSql("WHERE x.\"Inet\" >>= @__inet_1 = TRUE"); } } /// - /// Tests translation for . + /// Tests translation for . /// [Fact] - public void NpgsqlInetContainsOrEqualsNpgsqlInet() + public void ValueTuple_cidr_ContainsOrEquals_cidr() { using (NetContext context = Fixture.CreateContext()) { - NpgsqlInet npgsqlInet = new IPAddress(0); + (IPAddress Address, int Subnet) cidr = (new IPAddress(0), 0); NetTestEntity[] _ = context.NetTestEntities - .Where(x => EF.Functions.ContainsOrEquals(x.CidrMappedToNpgsqlInet, npgsqlInet)) + .Where(x => EF.Functions.ContainsOrEqual(x.Cidr, cidr)) .ToArray(); - AssertContainsSql("WHERE x.\"CidrMappedToNpgsqlInet\" >>= @__npgsqlInet_0"); + AssertContainsSql("WHERE x.\"Cidr\" >>= @__cidr_1 = TRUE"); } } @@ -174,37 +172,37 @@ public void NpgsqlInetContainsOrEqualsNpgsqlInet() /// Tests inverse translation for . /// [Fact] - public void IPAddressDoesNotContainOrEqualIPAddress() + public void IPAddress_inet_DoesNotContainOrEqual_inet() { using (NetContext context = Fixture.CreateContext()) { - IPAddress address = new IPAddress(0); + IPAddress inet = new IPAddress(0); NetTestEntity[] _ = context.NetTestEntities - .Where(x => !EF.Functions.ContainsOrEquals(x.InetMappedToIPAddress, address)) + .Where(x => !EF.Functions.ContainsOrEqual(x.Inet, inet)) .ToArray(); - AssertContainsSql("WHERE NOT (x.\"InetMappedToIPAddress\" >>= @__address_0 = TRUE)"); + AssertContainsSql("WHERE NOT (x.\"Inet\" >>= @__inet_1 = TRUE)"); } } /// - /// Tests inverse translation for . + /// Tests inverse translation for . /// [Fact] - public void NpgsqlInetDoesNotContainOrEqualNpgsqlInet() + public void ValueTuple_cidr_DoesNotContainOrEqual_cidr() { using (NetContext context = Fixture.CreateContext()) { - NpgsqlInet npgsqlInet = new IPAddress(0); + (IPAddress Address, int Subnet) cidr = (new IPAddress(0), 0); NetTestEntity[] _ = context.NetTestEntities - .Where(x => !EF.Functions.ContainsOrEquals(x.CidrMappedToNpgsqlInet, npgsqlInet)) + .Where(x => !EF.Functions.ContainsOrEqual(x.Cidr, cidr)) .ToArray(); - AssertContainsSql("WHERE NOT (x.\"CidrMappedToNpgsqlInet\" >>= @__npgsqlInet_0 = TRUE)"); + AssertContainsSql("WHERE NOT (x.\"Cidr\" >>= @__cidr_1 = TRUE)"); } } @@ -256,18 +254,18 @@ public NetworkAddressQueryNpgsqlFixture() { 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) }); +// BUG: This throws for some reason +// for (int i = 0; i < 10; i++) +// { +// context.NetTestEntities +// .Add( +// new NetTestEntity +// { +// Id = i, +// Inet = new IPAddress(i), +// Cidr = (IPAddress: new IPAddress(i), Subnet: i) +// }); +// } context.SaveChanges(); } @@ -305,14 +303,12 @@ public class NetTestEntity /// /// The network address. /// - [Column(TypeName = "inet")] - public IPAddress InetMappedToIPAddress { get; set; } + public IPAddress Inet { get; set; } /// /// The network address. /// - [Column(TypeName = "cidr")] - public NpgsqlInet CidrMappedToNpgsqlInet { get; set; } + public (IPAddress IPAddress, int Subnet) Cidr { get; set; } } ///