Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Map range operations for NpgsqlRange<T> #323

Merged
merged 6 commits into from
May 15, 2018
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
253 changes: 253 additions & 0 deletions src/EFCore.PG/NpgsqlRangeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
#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 Npgsql.EntityFrameworkCore.PostgreSQL.Query.ExpressionTranslators;
using NpgsqlTypes;

namespace Npgsql.EntityFrameworkCore.PostgreSQL
{
/// <summary>
/// Provides extension methods for <see cref="NpgsqlRange{T}"/> supporting PostgreSQL translation.
/// </summary>
public static class NpgsqlRangeExtensions
{
/// <summary>
/// Determines whether a range contains a specified value.
/// </summary>
/// <param name="range">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: here and below, why not put the <param> and <typeparam> in a single line:

/// <param name="range">The range in which to locate the value</param>

This seems to be standard in the .NET / EF Core code bases and reduces lots of useless lines

/// The range in which to locate the value.
/// </param>
/// <param name="value">
/// The value to locate in the range.
/// </param>
/// <typeparam name="T">
/// The type of the elements of <paramref name="range"/>.
/// </typeparam>
/// <returns>
/// <value>true</value> if the range contains the specified value; otherwise, <value>false</value>.
/// </returns>
[NpgsqlRangeOperator(NpgsqlRangeOperatorType.Contains)]
public static bool Contains<T>(this NpgsqlRange<T> range, T value) where T : IComparable<T> => throw new NotImplementedException();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should throw NotSupportException, not NotImplementedException.


/// <summary>
/// Determines whether a range contains a specified range.
/// </summary>
/// <param name="a">
/// The range in which to locate the specified range.
/// </param>
/// <param name="b">
/// The specified range to locate in the range.
/// </param>
/// <typeparam name="T">
/// The type of the elements of <paramref name="a"/>.
/// </typeparam>
/// <returns>
/// <value>true</value> if the range contains the specified range; otherwise, <value>false</value>.
/// </returns>
[NpgsqlRangeOperator(NpgsqlRangeOperatorType.Contains)]
public static bool Contains<T>(this NpgsqlRange<T> a, NpgsqlRange<T> b) where T : IComparable<T> => throw new NotImplementedException();

/// <summary>
/// Determines whether a range is contained by a specified range.
/// </summary>
/// <param name="a">
/// The specified range to locate in the range.
/// </param>
/// <param name="b">
/// The range in which to locate the specified range.
/// </param>
/// <typeparam name="T">
/// The type of the elements of <paramref name="a"/>.
/// </typeparam>
/// <returns>
/// <value>true</value> if the range contains the specified range; otherwise, <value>false</value>.
/// </returns>
[NpgsqlRangeOperator(NpgsqlRangeOperatorType.ContainedBy)]
public static bool ContainedBy<T>(this NpgsqlRange<T> a, NpgsqlRange<T> b) where T : IComparable<T> => b.Contains(a);

/// <summary>
/// Determines whether a range overlaps another range.
/// </summary>
/// <param name="a">
/// The first range.
/// </param>
/// <param name="b">
/// The second range.
/// </param>
/// <typeparam name="T">
/// The type of the elements of <paramref name="a"/>.
/// </typeparam>
/// <returns>
/// <value>true</value> if the ranges overlap (share points in common); otherwise, <value>false</value>.
/// </returns>
[NpgsqlRangeOperator(NpgsqlRangeOperatorType.Overlaps)]
public static bool Overlaps<T>(this NpgsqlRange<T> a, NpgsqlRange<T> b) where T : IComparable<T> => throw new NotImplementedException();

/// <summary>
/// Determines whether a range is strictly to the left of another range.
/// </summary>
/// <param name="a">
/// The first range.
/// </param>
/// <param name="b">
/// The second range.
/// </param>
/// <typeparam name="T">
/// The type of the elements of <paramref name="a"/>.
/// </typeparam>
/// <returns>
/// <value>true</value> if the first range is strictly to the left of the second; otherwise, <value>false</value>.
/// </returns>
[NpgsqlRangeOperator(NpgsqlRangeOperatorType.IsStrictlyLeftOf)]
public static bool IsStrictlyLeftOf<T>(this NpgsqlRange<T> a, NpgsqlRange<T> b) where T : IComparable<T> => throw new NotImplementedException();

/// <summary>
/// Determines whether a range is strictly to the right of another range.
/// </summary>
/// <param name="a">
/// The first range.
/// </param>
/// <param name="b">
/// The second range.
/// </param>
/// <typeparam name="T">
/// The type of the elements of <paramref name="a"/>.
/// </typeparam>
/// <returns>
/// <value>true</value> if the first range is strictly to the right of the second; otherwise, <value>false</value>.
/// </returns>
[NpgsqlRangeOperator(NpgsqlRangeOperatorType.IsStrictlyRightOf)]
public static bool IsStrictlyRightOf<T>(this NpgsqlRange<T> a, NpgsqlRange<T> b) where T : IComparable<T> => throw new NotImplementedException();

/// <summary>
/// Determines whether a range does not extend to the left of another range.
/// </summary>
/// <param name="a">
/// The first range.
/// </param>
/// <param name="b">
/// The second range.
/// </param>
/// <typeparam name="T">
/// The type of the elements of <paramref name="a"/>.
/// </typeparam>
/// <returns>
/// <value>true</value> if the first range does not extend to the left of the second; otherwise, <value>false</value>.
/// </returns>
[NpgsqlRangeOperator(NpgsqlRangeOperatorType.DoesNotExtendLeftOf)]
public static bool DoesNotExtendLeftOf<T>(this NpgsqlRange<T> a, NpgsqlRange<T> b) where T : IComparable<T> => throw new NotImplementedException();

/// <summary>
/// Determines whether a range does not extend to the right of another range.
/// </summary>
/// <param name="a">
/// The first range.
/// </param>
/// <param name="b">
/// The second range.
/// </param>
/// <typeparam name="T">
/// The type of the elements of <paramref name="a"/>.
/// </typeparam>
/// <returns>
/// <value>true</value> if the first range does not extend to the right of the second; otherwise, <value>false</value>.
/// </returns>
[NpgsqlRangeOperator(NpgsqlRangeOperatorType.DoesNotExtendRightOf)]
public static bool DoesNotExtendRightOf<T>(this NpgsqlRange<T> a, NpgsqlRange<T> b) where T : IComparable<T> => throw new NotImplementedException();

/// <summary>
/// Determines whether a range is adjacent to another range.
/// </summary>
/// <param name="a">
/// The first range.
/// </param>
/// <param name="b">
/// The second range.
/// </param>
/// <typeparam name="T">
/// The type of the elements of <paramref name="a"/>.
/// </typeparam>
/// <returns>
/// <value>true</value> if the ranges are adjacent; otherwise, <value>false</value>.
/// </returns>
[NpgsqlRangeOperator(NpgsqlRangeOperatorType.IsAdjacentTo)]
public static bool IsAdjacentTo<T>(this NpgsqlRange<T> a, NpgsqlRange<T> b) where T : IComparable<T> => throw new NotImplementedException();

/// <summary>
/// Returns the set union, which means unique elements that appear in either of two ranges.
/// </summary>
/// <param name="a">
/// The first range.
/// </param>
/// <param name="b">
/// The second range.
/// </param>
/// <typeparam name="T">
/// The type of the elements of <paramref name="a"/>.
/// </typeparam>
/// <returns>
/// The unique elements that appear in either range.
/// </returns>
[NpgsqlRangeOperator(NpgsqlRangeOperatorType.Union)]
public static NpgsqlRange<T> Union<T>(this NpgsqlRange<T> a, NpgsqlRange<T> b) where T : IComparable<T> => throw new NotImplementedException();

/// <summary>
/// Returns the set intersection, which means elements that appear in each of two ranges.
/// </summary>
/// <param name="a">
/// The first range.
/// </param>
/// <param name="b">
/// The second range.
/// </param>
/// <typeparam name="T">
/// The type of the elements of <paramref name="a"/>.
/// </typeparam>
/// <returns>
/// The elements that appear in both ranges.
/// </returns>
[NpgsqlRangeOperator(NpgsqlRangeOperatorType.Intersection)]
public static NpgsqlRange<T> Intersect<T>(this NpgsqlRange<T> a, NpgsqlRange<T> b) where T : IComparable<T> => throw new NotImplementedException();

/// <summary>
/// Returns the set difference, which means the elements of one range that do not appear in a second range.
/// </summary>
/// <param name="a">
/// The first range.
/// </param>
/// <param name="b">
/// The second range.
/// </param>
/// <typeparam name="T">
/// The type of the elements of <paramref name="a"/>.
/// </typeparam>
/// <returns>
/// The elements that appear in the first range, but not the second range.
/// </returns>
[NpgsqlRangeOperator(NpgsqlRangeOperatorType.Difference)]
public static NpgsqlRange<T> Except<T>(this NpgsqlRange<T> a, NpgsqlRange<T> b) where T : IComparable<T> => throw new NotImplementedException();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#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 Npgsql.EntityFrameworkCore.PostgreSQL.Query.Expressions.Internal;
using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities;

namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query.ExpressionTranslators.Internal
{
/// <summary>
/// Represents information about a PostgreSQL operator.
/// </summary>
/// <remarks>
/// This attribute stores metadata describing the representation of a binary operator
/// in PostgreSQL on enum members representing the available binary operators for a PostgreSQL type.
/// </remarks>
[AttributeUsage(AttributeTargets.Field)]
internal class NpgsqlBinaryOperatorAttribute : Attribute
{
/// <summary>
/// The operator symbol.
/// </summary>
[NotNull]
public string Symbol { get; set; } = string.Empty;

/// <summary>
/// The operator represented by the method.
/// </summary>
[NotNull]
public Type ReturnType { get; set; } = typeof(void);

/// <summary>
/// Creates a <see cref="CustomBinaryExpression"/> representing the operator.
/// </summary>
/// <param name="left">
/// The left-hand expression.
/// </param>
/// <param name="right">
/// The right-hand expression.
/// </param>
/// <returns>
/// A <see cref="CustomBinaryExpression"/> representing the operator.
/// </returns>
/// <exception cref="ArgumentNullException"/>
[NotNull]
public Expression Create([NotNull] Expression left, [NotNull] Expression right)
{
Check.NotNull(left, nameof(left));
Check.NotNull(right, nameof(right));

// TODO: will the left type arguments always be valid?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my general comment about the architecture. Simply moving all the logic into the translator makes this go away, as you'd be translating each operation separately and can make this decision on a per-operation basis.

Type type = ReturnType.IsGenericType ? ReturnType.MakeGenericType(left.Type.GetGenericArguments()) : ReturnType;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: please use var everywhere


return new CustomBinaryExpression(left, right, Symbol, type);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ public class NpgsqlCompositeMethodCallTranslator : RelationalCompositeMethodCall
new NpgsqlStringTrimEndTranslator(),
new NpgsqlStringTrimStartTranslator(),
new NpgsqlRegexIsMatchTranslator(),
new NpgsqlFullTextSearchMethodTranslator()
new NpgsqlFullTextSearchMethodTranslator(),
new NpgsqlRangeOperatorTranslator()
};

public NpgsqlCompositeMethodCallTranslator(
Expand Down
Loading