diff --git a/src/EFCore.PG/Query/Expressions/Internal/ArrayAnyAllExpression.cs b/src/EFCore.PG/Query/Expressions/Internal/ArrayAnyAllExpression.cs index f7d15efc9..66d3338f3 100644 --- a/src/EFCore.PG/Query/Expressions/Internal/ArrayAnyAllExpression.cs +++ b/src/EFCore.PG/Query/Expressions/Internal/ArrayAnyAllExpression.cs @@ -93,23 +93,20 @@ public ArrayAnyAllExpression( /// protected override Expression Accept(ExpressionVisitor visitor) - => visitor is NpgsqlQuerySqlGenerator npsgqlGenerator - ? npsgqlGenerator.VisitArrayAnyAll(this) + => visitor is NpgsqlQuerySqlGenerator npgsqlGenerator + ? npgsqlGenerator.VisitArrayAnyAll(this) : base.Accept(visitor); /// protected override Expression VisitChildren(ExpressionVisitor visitor) { - if (!(visitor.Visit(Operand) is Expression operand)) - throw new ArgumentException($"The {nameof(operand)} of a {nameof(ArrayAnyAllExpression)} cannot be null."); - - if (!(visitor.Visit(Array) is Expression collection)) - throw new ArgumentException($"The {nameof(collection)} of a {nameof(ArrayAnyAllExpression)} cannot be null."); + var operand = visitor.Visit(Operand) ?? Operand; + var array = visitor.Visit(Array) ?? Array; return - operand == Operand && collection == Array - ? this - : new ArrayAnyAllExpression(ArrayComparisonType, Operator, operand, collection); + operand != Operand || array != Array + ? new ArrayAnyAllExpression(ArrayComparisonType, Operator, operand, array) + : this; } /// @@ -131,8 +128,7 @@ public override int GetHashCode() (397 * Array.GetHashCode())); /// - public override string ToString() - => $"{Operand} {Operator} {ArrayComparisonType.ToString()} ({Array})"; + public override string ToString() => $"{Operand} {Operator} {ArrayComparisonType.ToString()} ({Array})"; } /// diff --git a/src/EFCore.PG/Query/Expressions/Internal/AtTimeZoneExpression.cs b/src/EFCore.PG/Query/Expressions/Internal/AtTimeZoneExpression.cs index e0021edb9..8528e8e05 100644 --- a/src/EFCore.PG/Query/Expressions/Internal/AtTimeZoneExpression.cs +++ b/src/EFCore.PG/Query/Expressions/Internal/AtTimeZoneExpression.cs @@ -1,4 +1,5 @@ #region License + // The PostgreSQL License // // Copyright (C) 2016 The Npgsql Development Team @@ -19,6 +20,7 @@ // 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; @@ -29,42 +31,59 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query.Expressions.Internal { + /// + /// Represents a PostgreSQL AT TIME ZONE expression. + /// public class AtTimeZoneExpression : Expression { - public AtTimeZoneExpression([NotNull] Expression timestampExpression, [NotNull] string timeZone) - { - Check.NotNull(timestampExpression, nameof(timestampExpression)); - Check.NotNull(timeZone, nameof(timeZone)); - - TimestampExpression = timestampExpression; - TimeZone = timeZone; - } - - public Expression TimestampExpression { get; } - public string TimeZone { get; } - + /// public override ExpressionType NodeType => ExpressionType.Extension; + /// public override Type Type => typeof(DateTime); - protected override Expression Accept([NotNull] ExpressionVisitor visitor) + /// + /// The timestamp. + /// + [NotNull] + public Expression Timestamp { get; } + + /// + /// The time zone. + /// + [NotNull] + public string TimeZone { get; } + + /// + /// Constructs an . + /// + /// The timestamp. + /// The time zone. + /// + public AtTimeZoneExpression([NotNull] Expression timestamp, [NotNull] string timeZone) { - Check.NotNull(visitor, nameof(visitor)); + Timestamp = Check.NotNull(timestamp, nameof(timestamp)); + TimeZone = Check.NotNull(timeZone, nameof(timeZone)); + } - return visitor is NpgsqlQuerySqlGenerator npgsqlGenerator + /// + protected override Expression Accept(ExpressionVisitor visitor) + => visitor is NpgsqlQuerySqlGenerator npgsqlGenerator ? npgsqlGenerator.VisitAtTimeZone(this) : base.Accept(visitor); - } + /// protected override Expression VisitChildren(ExpressionVisitor visitor) { - var newTimestampExpression = visitor.Visit(TimestampExpression); + var timestamp = visitor.Visit(Timestamp) ?? Timestamp; - return newTimestampExpression != TimestampExpression - ? new AtTimeZoneExpression(newTimestampExpression, TimeZone) - : this; + return + timestamp != Timestamp + ? new AtTimeZoneExpression(timestamp, TimeZone) + : this; } - public override string ToString() => $"{TimestampExpression} AT TIME ZONE {TimeZone}"; + /// + public override string ToString() => $"{Timestamp} AT TIME ZONE {TimeZone}"; } } diff --git a/src/EFCore.PG/Query/Expressions/Internal/CustomBinaryExpression.cs b/src/EFCore.PG/Query/Expressions/Internal/CustomBinaryExpression.cs index 617dbf1d6..17999c558 100644 --- a/src/EFCore.PG/Query/Expressions/Internal/CustomBinaryExpression.cs +++ b/src/EFCore.PG/Query/Expressions/Internal/CustomBinaryExpression.cs @@ -1,10 +1,8 @@ using System; -using System.Linq; using System.Linq.Expressions; using JetBrains.Annotations; using Npgsql.EntityFrameworkCore.PostgreSQL.Query.Sql.Internal; using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities; -using NpgsqlTypes; namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query.Expressions.Internal { @@ -14,49 +12,69 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query.Expressions.Internal /// public class CustomBinaryExpression : Expression { + /// + public override ExpressionType NodeType => ExpressionType.Extension; + + /// + public override Type Type { get; } + + /// + /// The left-hand expression. + /// + [NotNull] + public Expression Left { get; } + + /// + /// The right-hand expression. + /// + [NotNull] + public Expression Right { get; } + + /// + /// The operator. + /// + [NotNull] + public string Operator { get; } + + /// + /// Constructs a . + /// + /// The left-hand expression. + /// The right-hand expression. + /// The operator symbol acting on the expression. + /// The result type. + /// public CustomBinaryExpression( [NotNull] Expression left, [NotNull] Expression right, [NotNull] string binaryOperator, [NotNull] Type type) { - Check.NotNull(right, nameof(right)); - Check.NotNull(left, nameof(left)); - Check.NotEmpty(binaryOperator, nameof(binaryOperator)); - Check.NotNull(type, nameof(type)); - - Left = left; - Right = right; - Operator = binaryOperator; - Type = type; + Left = Check.NotNull(left, nameof(left)); + Right = Check.NotNull(right, nameof(right)); + Operator = Check.NotEmpty(binaryOperator, nameof(binaryOperator)); + Type = Check.NotNull(type, nameof(type)); } - public Expression Left { get; } - public Expression Right { get; } - public string Operator { get; } - public override Type Type { get; } - - public override ExpressionType NodeType => ExpressionType.Extension; - + /// protected override Expression Accept(ExpressionVisitor visitor) - { - Check.NotNull(visitor, nameof(visitor)); - - return visitor is NpgsqlQuerySqlGenerator npgsqlGenerator + => visitor is NpgsqlQuerySqlGenerator npgsqlGenerator ? npgsqlGenerator.VisitCustomBinary(this) : base.Accept(visitor); - } + /// protected override Expression VisitChildren(ExpressionVisitor visitor) { - var newLeft = visitor.Visit(Left); - var newRight = visitor.Visit(Right); + var left = visitor.Visit(Left) ?? Left; + var right = visitor.Visit(Right) ?? Right; - return newLeft != Left || newRight != Right - ? new CustomBinaryExpression(newLeft, newRight, Operator, Type) - : this; + return + left != Left || right != Right + ? new CustomBinaryExpression(left, right, Operator, Type) + : this; } + /// public override string ToString() => $"{Left} {Operator} {Right}"; } } diff --git a/src/EFCore.PG/Query/Expressions/Internal/CustomUnaryExpression.cs b/src/EFCore.PG/Query/Expressions/Internal/CustomUnaryExpression.cs index 5a3bd7d46..b2bb7b8b2 100644 --- a/src/EFCore.PG/Query/Expressions/Internal/CustomUnaryExpression.cs +++ b/src/EFCore.PG/Query/Expressions/Internal/CustomUnaryExpression.cs @@ -1,10 +1,8 @@ using System; -using System.Linq; using System.Linq.Expressions; using JetBrains.Annotations; using Npgsql.EntityFrameworkCore.PostgreSQL.Query.Sql.Internal; using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities; -using NpgsqlTypes; namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query.Expressions.Internal { @@ -14,49 +12,67 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query.Expressions.Internal /// public class CustomUnaryExpression : Expression { - public CustomUnaryExpression( - [NotNull] Expression operand, - [NotNull] string @operator, - [NotNull] Type type, - bool postfix=false) - { - Check.NotNull(operand, nameof(operand)); - Check.NotEmpty(@operator, nameof(@operator)); - Check.NotNull(type, nameof(type)); + /// + public override ExpressionType NodeType => ExpressionType.Extension; - Operand = operand; - Operator = @operator; - Type = type; - Postfix = postfix; - } + /// + public override Type Type { get; } + /// + /// The expression acted on by the operator. + /// + [NotNull] public Expression Operand { get; } + + /// + /// The operator. + /// + [NotNull] public string Operator { get; } - public override Type Type { get; } - public bool Postfix { get; } - public override ExpressionType NodeType => ExpressionType.Extension; + /// + /// True if the operator follows the operand; otherwise, false. + /// + public bool Postfix { get; } - protected override Expression Accept(ExpressionVisitor visitor) + /// + /// Constructs a . + /// + /// The expression acted on by the . + /// The operator symbol acting on the expression. + /// The result type. + /// True if the follows the operand; otherwise, false. + /// + public CustomUnaryExpression( + [NotNull] Expression operand, + [NotNull] string unaryOperator, + [NotNull] Type type, + bool postfix = false) { - Check.NotNull(visitor, nameof(visitor)); + Operand = Check.NotNull(operand, nameof(operand)); + Operator = Check.NotEmpty(unaryOperator, nameof(unaryOperator)); + Type = Check.NotNull(type, nameof(type)); + Postfix = postfix; + } - return visitor is NpgsqlQuerySqlGenerator npgsqlGenerator + /// + protected override Expression Accept(ExpressionVisitor visitor) + => visitor is NpgsqlQuerySqlGenerator npgsqlGenerator ? npgsqlGenerator.VisitCustomUnary(this) : base.Accept(visitor); - } + /// protected override Expression VisitChildren(ExpressionVisitor visitor) { - var newOperand = visitor.Visit(Operand); + var operand = visitor.Visit(Operand) ?? Operand; - return newOperand != Operand - ? new CustomUnaryExpression(newOperand, Operator, Type) - : this; + return + operand != Operand + ? new CustomUnaryExpression(operand, Operator, Type) + : this; } - public override string ToString() => Postfix - ? $"{Operator}{Operand}" - : $"{Operand}{Operator}"; + /// + public override string ToString() => Postfix ? $"{Operator}{Operand}" : $"{Operand}{Operator}"; } } diff --git a/src/EFCore.PG/Query/Expressions/Internal/ExplicitStoreTypeCastExpression.cs b/src/EFCore.PG/Query/Expressions/Internal/ExplicitStoreTypeCastExpression.cs index 68e2352bb..73e631d6b 100644 --- a/src/EFCore.PG/Query/Expressions/Internal/ExplicitStoreTypeCastExpression.cs +++ b/src/EFCore.PG/Query/Expressions/Internal/ExplicitStoreTypeCastExpression.cs @@ -1,4 +1,5 @@ #region License + // The PostgreSQL License // // Copyright (C) 2016 The Npgsql Development Team @@ -19,6 +20,7 @@ // 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; @@ -30,132 +32,77 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query.Expressions.Internal { /// - /// Represents a SQL CAST expression to a store type specified as a string rather than a CLR type. + /// Represents a SQL CAST expression to a store type specified as a string rather than a CLR type. /// - public class ExplicitStoreTypeCastExpression : Expression + public class ExplicitStoreTypeCastExpression : Expression, IEquatable { - readonly Type _type; - readonly string _storeType; - - /// - /// Creates a new instance of a ExplicitCastExpression.. - /// - /// The operand. - /// The target type. - /// The store type name. - public ExplicitStoreTypeCastExpression( - [NotNull] Expression operand, - [NotNull] Type type, - [NotNull] string storeType) - { - Check.NotNull(operand, nameof(operand)); - Check.NotNull(type, nameof(type)); - Check.NotNull(storeType, nameof(storeType)); + /// + public override ExpressionType NodeType => ExpressionType.Extension; - Operand = operand; - _type = type; - _storeType = storeType; - } + /// + public override Type Type { get; } /// - /// Gets the operand. + /// The operand. /// - /// - /// The operand. - /// + [NotNull] public virtual Expression Operand { get; } /// - /// Returns the node type of this . (Inherited from .) - /// - /// The that represents this expression. - public override ExpressionType NodeType => ExpressionType.Extension; - - /// - /// Gets the static type of the expression that this represents. (Inherited from .) + /// The store type name. /// - /// The that represents the static type of the expression. - public override Type Type => _type; - - public string StoreType=> _storeType; + [NotNull] + public string StoreType { get; } /// - /// Dispatches to the specific visit method for this node type. + /// Constructs a . /// - protected override Expression Accept(ExpressionVisitor visitor) + /// The operand. + /// The target type. + /// The store type name. + public ExplicitStoreTypeCastExpression( + [NotNull] Expression operand, + [NotNull] Type type, + [NotNull] string storeType) { - Check.NotNull(visitor, nameof(visitor)); + Operand = Check.NotNull(operand, nameof(operand)); + Type = Check.NotNull(type, nameof(type)); + StoreType = Check.NotNull(storeType, nameof(storeType)); + } - return visitor is NpgsqlQuerySqlGenerator npgsqlVisitor - ? npgsqlVisitor.VisitExplicitStoreTypeCast(this) + /// + protected override Expression Accept(ExpressionVisitor visitor) + => visitor is NpgsqlQuerySqlGenerator npgsqlGenerator + ? npgsqlGenerator.VisitExplicitStoreTypeCast(this) : base.Accept(visitor); - } - /// - /// Reduces the node and then calls the method passing the - /// reduced expression. - /// Throws an exception if the node isn't reducible. - /// - /// An instance of . - /// The expression being visited, or an expression which should replace it in the tree. - /// - /// Override this method to provide logic to walk the node's children. - /// A typical implementation will call visitor.Visit on each of its - /// children, and if any of them change, should return a new copy of - /// itself with the modified children. - /// + /// protected override Expression VisitChildren(ExpressionVisitor visitor) { - var newOperand = visitor.Visit(Operand); + var operand = visitor.Visit(Operand) ?? Operand; - return newOperand != Operand - ? new ExplicitStoreTypeCastExpression(newOperand, _type, _storeType) - : this; + return + operand != Operand + ? new ExplicitStoreTypeCastExpression(operand, Type, StoreType) + : this; } - /// - /// Tests if this object is considered equal to another. - /// - /// The object to compare with the current object. - /// - /// true if the objects are considered equal, false if they are not. - /// + /// public override bool Equals(object obj) - { - if (obj is null) - { - return false; - } + => obj is ExplicitStoreTypeCastExpression other && Equals(other); - if (ReferenceEquals(this, obj)) - { - return true; - } + /// + public bool Equals(ExplicitStoreTypeCastExpression other) + => other != null && + Type == other.Type && + StoreType == other.StoreType && + Equals(Operand, other.Operand); - return obj.GetType() == GetType() && Equals((ExplicitStoreTypeCastExpression)obj); - } - - private bool Equals(ExplicitStoreTypeCastExpression other) - => _type == other._type && _storeType == other._storeType && Equals(Operand, other.Operand); - - /// - /// Returns a hash code for this object. - /// - /// - /// A hash code for this object. - /// + /// public override int GetHashCode() - { - unchecked - { - return (_type.GetHashCode() * 397) ^ (_storeType.GetHashCode() * 397) ^ Operand.GetHashCode(); - } - } + => unchecked((Type.GetHashCode() * 397) ^ (StoreType.GetHashCode() * 397) ^ Operand.GetHashCode()); - /// - /// Creates a representation of the Expression. - /// - /// A representation of the Expression. - public override string ToString() => "CAST(" + Operand + " AS " + _storeType + ")"; + /// + public override string ToString() => $"CAST({Operand} AS {StoreType})"; } } diff --git a/src/EFCore.PG/Query/Expressions/Internal/ILikeExpression.cs b/src/EFCore.PG/Query/Expressions/Internal/ILikeExpression.cs index 78fa7777d..2f5c4b64c 100644 --- a/src/EFCore.PG/Query/Expressions/Internal/ILikeExpression.cs +++ b/src/EFCore.PG/Query/Expressions/Internal/ILikeExpression.cs @@ -1,4 +1,5 @@ #region License + // The PostgreSQL License // // Copyright (C) 2016 The Npgsql Development Team @@ -19,162 +20,103 @@ // 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.Expressions; using Npgsql.EntityFrameworkCore.PostgreSQL.Query.Sql.Internal; using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities; namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query.Expressions.Internal { /// - /// Represents a SQL ILIKE expression. + /// Represents a PostgreSQL ILIKE expression. /// - public class ILikeExpression : Expression + // ReSharper disable once InconsistentNaming + public class ILikeExpression : Expression, IEquatable { - /// - /// Creates a new instance of LikeExpression. - /// - /// The expression to match. - /// The pattern to match. - public ILikeExpression([NotNull] Expression match, [NotNull] Expression pattern) - { - Check.NotNull(match, nameof(match)); - Check.NotNull(pattern, nameof(pattern)); - - Match = match; - Pattern = pattern; - } - - /// - /// Creates a new instance of LikeExpression. - /// - /// The expression to match. - /// The pattern to match. - /// The escape character to use in . - public ILikeExpression([NotNull] Expression match, [NotNull] Expression pattern, [CanBeNull] Expression escapeChar) - { - Check.NotNull(match, nameof(match)); - Check.NotNull(pattern, nameof(pattern)); + /// + public override ExpressionType NodeType => ExpressionType.Extension; - Match = match; - Pattern = pattern; - EscapeChar = escapeChar; - } + /// + public override Type Type => typeof(bool); /// - /// Gets the match expression. + /// The match expression. /// - /// - /// The match expression. - /// + [NotNull] public virtual Expression Match { get; } /// - /// Gets the pattern to match. + /// The pattern to match. /// - /// - /// The pattern to match. - /// + [NotNull] public virtual Expression Pattern { get; } /// - /// Gets the escape character to use in . + /// The escape character to use in . /// - /// - /// The escape character to use. If null, no escape character is used. - /// [CanBeNull] public virtual Expression EscapeChar { get; } /// - /// Returns the node type of this . (Inherited from .) - /// - /// The that represents this expression. - public override ExpressionType NodeType => ExpressionType.Extension; - - /// - /// Gets the static type of the expression that this represents. (Inherited from .) + /// Constructs a . /// - /// The that represents the static type of the expression. - public override Type Type => typeof(bool); + /// The expression to match. + /// The pattern to match. + /// + public ILikeExpression([NotNull] Expression match, [NotNull] Expression pattern) + { + Match = Check.NotNull(match, nameof(match)); + Pattern = Check.NotNull(pattern, nameof(pattern)); + } /// - /// Dispatches to the specific visit method for this node type. + /// Constructs a . /// - protected override Expression Accept(ExpressionVisitor visitor) + /// The expression to match. + /// The pattern to match. + /// The escape character to use in . + /// + public ILikeExpression([NotNull] Expression match, [NotNull] Expression pattern, [CanBeNull] Expression escapeChar) { - Check.NotNull(visitor, nameof(visitor)); - - var specificVisitor = visitor as NpgsqlQuerySqlGenerator; + Match = Check.NotNull(match, nameof(match)); + Pattern = Check.NotNull(pattern, nameof(pattern)); + EscapeChar = escapeChar; + } - return specificVisitor != null - ? specificVisitor.VisitILike(this) + /// + protected override Expression Accept(ExpressionVisitor visitor) + => visitor is NpgsqlQuerySqlGenerator npgsqlGenerator + ? npgsqlGenerator.VisitILike(this) : base.Accept(visitor); - } - /// - /// Reduces the node and then calls the method passing the - /// reduced expression. - /// Throws an exception if the node isn't reducible. - /// - /// An instance of . - /// The expression being visited, or an expression which should replace it in the tree. - /// - /// Override this method to provide logic to walk the node's children. - /// A typical implementation will call visitor.Visit on each of its - /// children, and if any of them change, should return a new copy of - /// itself with the modified children. - /// + /// protected override Expression VisitChildren(ExpressionVisitor visitor) { - var newMatchExpression = visitor.Visit(Match); - var newPatternExpression = visitor.Visit(Pattern); - var newEscapeCharExpression = EscapeChar == null ? null : visitor.Visit(EscapeChar); - - return newMatchExpression != Match - || newPatternExpression != Pattern - || newEscapeCharExpression != EscapeChar - ? new ILikeExpression(newMatchExpression, newPatternExpression, newEscapeCharExpression) - : this; + var match = visitor.Visit(Match) ?? Match; + var pattern = visitor.Visit(Pattern) ?? Pattern; + var escapeChar = visitor.Visit(EscapeChar); + + return + match != Match || pattern != Pattern || escapeChar != EscapeChar + ? new ILikeExpression(match, pattern, escapeChar) + : this; } - /// - /// Tests if this object is considered equal to another. - /// - /// The object to compare with the current object. - /// - /// true if the objects are considered equal, false if they are not. - /// - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) - { - return false; - } - - if (ReferenceEquals(this, obj)) - { - return true; - } - - return obj.GetType() == GetType() && Equals((ILikeExpression)obj); - } + /// + public override bool Equals(object obj) => obj is ILikeExpression other && Equals(other); - bool Equals(ILikeExpression other) - => Equals(Match, other.Match) - && Equals(Pattern, other.Pattern) - && Equals(EscapeChar, other.EscapeChar); + /// + public bool Equals(ILikeExpression other) + => other != null && + Equals(Match, other.Match) && + Equals(Pattern, other.Pattern) && + Equals(EscapeChar, other.EscapeChar); - /// - /// Returns a hash code for this object. - /// - /// - /// A hash code for this object. - /// + /// public override int GetHashCode() { unchecked @@ -182,15 +124,11 @@ public override int GetHashCode() var hashCode = Match.GetHashCode(); hashCode = (hashCode * 397) ^ Pattern.GetHashCode(); hashCode = (hashCode * 397) ^ (EscapeChar?.GetHashCode() ?? 0); - return hashCode; } } - /// - /// Creates a representation of the Expression. - /// - /// A representation of the Expression. + /// public override string ToString() => $"{Match} ILIKE {Pattern}{(EscapeChar == null ? "" : $" ESCAPE {EscapeChar}")}"; } } diff --git a/src/EFCore.PG/Query/Expressions/Internal/PgFunctionExpression.cs b/src/EFCore.PG/Query/Expressions/Internal/PgFunctionExpression.cs index ccb1fc548..1698c28b4 100644 --- a/src/EFCore.PG/Query/Expressions/Internal/PgFunctionExpression.cs +++ b/src/EFCore.PG/Query/Expressions/Internal/PgFunctionExpression.cs @@ -29,11 +29,11 @@ using System.Diagnostics; using System.Linq; using System.Linq.Expressions; -using System.Text; using JetBrains.Annotations; using Npgsql.EntityFrameworkCore.PostgreSQL.Query.Sql.Internal; using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities; +// ReSharper disable ArgumentsStyleLiteral namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query.Expressions.Internal { /// @@ -242,35 +242,30 @@ internal PgFunctionExpression( /// protected override Expression Accept(ExpressionVisitor visitor) - { - Check.NotNull(visitor, nameof(visitor)); - - return visitor is NpgsqlQuerySqlGenerator specificVisitor - ? specificVisitor.VisitPgFunction(this) + => visitor is NpgsqlQuerySqlGenerator npgsqlGenerator + ? npgsqlGenerator.VisitPgFunction(this) : base.Accept(visitor); - } /// protected override Expression VisitChildren(ExpressionVisitor visitor) { - var newInstance = visitor.Visit(Instance); - var newPositionalArguments = visitor.VisitAndConvert(_positionalArguments, nameof(VisitChildren)); + var instance = visitor.Visit(Instance) ?? Instance; + var positionalArguments = visitor.VisitAndConvert(_positionalArguments, nameof(VisitChildren)); - var newNamedArguments = new Dictionary(_namedArguments.Count); + var namedArguments = new Dictionary(_namedArguments.Count); var namedArgumentsChanged = false; foreach (var kv in _namedArguments) { var newExpression = visitor.Visit(kv.Value); if (newExpression != kv.Value) namedArgumentsChanged = true; - newNamedArguments[kv.Key] = newExpression; + namedArguments[kv.Key] = newExpression; } - return newInstance != Instance || - newPositionalArguments != _positionalArguments || - namedArgumentsChanged - ? new PgFunctionExpression(newInstance, FunctionName, Schema, Type, newPositionalArguments, newNamedArguments) - : this; + return + instance != Instance || positionalArguments != _positionalArguments || namedArgumentsChanged + ? new PgFunctionExpression(instance, FunctionName, Schema, Type, positionalArguments, namedArguments) + : this; } /// diff --git a/src/EFCore.PG/Query/Expressions/Internal/RegexMatchExpression.cs b/src/EFCore.PG/Query/Expressions/Internal/RegexMatchExpression.cs index 69c052323..03cb4d85d 100644 --- a/src/EFCore.PG/Query/Expressions/Internal/RegexMatchExpression.cs +++ b/src/EFCore.PG/Query/Expressions/Internal/RegexMatchExpression.cs @@ -1,4 +1,5 @@ #region License + // The PostgreSQL License // // Copyright (C) 2016 The Npgsql Development Team @@ -19,12 +20,14 @@ // 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 System.Text.RegularExpressions; using JetBrains.Annotations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Query.ExpressionVisitors; using Npgsql.EntityFrameworkCore.PostgreSQL.Query.Sql.Internal; using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities; @@ -32,44 +35,62 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query.Expressions.Internal { public class RegexMatchExpression : Expression { - public RegexMatchExpression([NotNull] Expression match, [NotNull] Expression pattern, RegexOptions options) - { - Check.NotNull(match, nameof(match)); - Check.NotNull(pattern, nameof(pattern)); + /// + public override ExpressionType NodeType => ExpressionType.Extension; - Match = match; - Pattern = pattern; - Options = options; - } + /// + public override Type Type => typeof(bool); - public Expression Match { get; } - public Expression Pattern { get; } - public RegexOptions Options { get; } + /// + /// The match expression. + /// + [NotNull] + public virtual Expression Match { get; } - public override ExpressionType NodeType => ExpressionType.Extension; + /// + /// The pattern to match. + /// + [NotNull] + public virtual Expression Pattern { get; } - public override Type Type => typeof(bool); + /// + /// The options for regular expression evaluation. + /// + public RegexOptions Options { get; } - protected override Expression Accept([NotNull] ExpressionVisitor visitor) + /// + /// Constructs a . + /// + /// The expression to match. + /// The pattern to match. + /// The options for regular expression evaluation. + /// + public RegexMatchExpression([NotNull] Expression match, [NotNull] Expression pattern, RegexOptions options) { - Check.NotNull(visitor, nameof(visitor)); + Match = Check.NotNull(match, nameof(match)); + Pattern = Check.NotNull(pattern, nameof(pattern)); + Options = options; + } - return visitor is NpgsqlQuerySqlGenerator npsgqlGenerator - ? npsgqlGenerator.VisitRegexMatch(this) + /// + protected override Expression Accept(ExpressionVisitor visitor) + => visitor is NpgsqlQuerySqlGenerator npgsqlGenerator + ? npgsqlGenerator.VisitRegexMatch(this) : base.Accept(visitor); - } + /// protected override Expression VisitChildren(ExpressionVisitor visitor) { - var newMatchExpression = visitor.Visit(Match); - var newPatternExpression = visitor.Visit(Pattern); + var match = visitor.Visit(Match) ?? Match; + var pattern = visitor.Visit(Pattern) ?? Pattern; - return newMatchExpression != Match - || newPatternExpression != Pattern - ? new RegexMatchExpression(newMatchExpression, newPatternExpression, Options) - : this; + return + match != Match || pattern != Pattern + ? new RegexMatchExpression(match, pattern, Options) + : this; } + /// public override string ToString() => $"{Match} ~ {Pattern}"; } } diff --git a/src/EFCore.PG/Query/Sql/Internal/NpgsqlQuerySqlGenerator.cs b/src/EFCore.PG/Query/Sql/Internal/NpgsqlQuerySqlGenerator.cs index 409320efc..6971349c1 100644 --- a/src/EFCore.PG/Query/Sql/Internal/NpgsqlQuerySqlGenerator.cs +++ b/src/EFCore.PG/Query/Sql/Internal/NpgsqlQuerySqlGenerator.cs @@ -186,15 +186,16 @@ protected override Expression VisitBinary(BinaryExpression expression) return exp; } - break; + goto default; } case ExpressionType.ArrayIndex: VisitArrayIndex(expression); return expression; - } - return base.VisitBinary(expression); + default: + return base.VisitBinary(expression); + } } /// @@ -241,35 +242,42 @@ protected virtual void VisitArrayIndex([NotNull] BinaryExpression expression) /// /// Produces expressions like: 1 = ANY ('{0,1,2}') or 'cat' LIKE ANY ('{a%,b%,c%}'). /// - public virtual Expression VisitArrayAnyAll([NotNull] ArrayAnyAllExpression arrayAnyAllExpression) + public virtual Expression VisitArrayAnyAll([NotNull] ArrayAnyAllExpression expression) { - Visit(arrayAnyAllExpression.Operand); + Visit(expression.Operand); Sql.Append(' '); - Sql.Append(arrayAnyAllExpression.Operator); + Sql.Append(expression.Operator); Sql.Append(' '); - Sql.Append(arrayAnyAllExpression.ArrayComparisonType.ToString()); + Sql.Append(expression.ArrayComparisonType.ToString()); Sql.Append(" ("); - Visit(arrayAnyAllExpression.Array); + Visit(expression.Array); Sql.Append(')'); - return arrayAnyAllExpression; + return expression; } /// - /// See: http://www.postgresql.org/docs/current/static/functions-matching.html + /// Visits the children of a . /// - public virtual Expression VisitRegexMatch([NotNull] RegexMatchExpression regexMatchExpression) + /// The expression. + /// + /// An . + /// + /// + /// See: http://www.postgresql.org/docs/current/static/functions-matching.html + /// + [NotNull] + public virtual Expression VisitRegexMatch([NotNull] RegexMatchExpression expression) { - Check.NotNull(regexMatchExpression, nameof(regexMatchExpression)); - var options = regexMatchExpression.Options; + var options = expression.Options; - Visit(regexMatchExpression.Match); + Visit(expression.Match); Sql.Append(" ~ "); // PG regexps are singleline by default if (options == RegexOptions.Singleline) { - Visit(regexMatchExpression.Pattern); - return regexMatchExpression; + Visit(expression.Pattern); + return expression; } Sql.Append("('(?"); @@ -286,71 +294,97 @@ public virtual Expression VisitRegexMatch([NotNull] RegexMatchExpression regexMa Sql.Append('x'); Sql.Append(")' || "); - Visit(regexMatchExpression.Pattern); + Visit(expression.Pattern); Sql.Append(')'); - return regexMatchExpression; + return expression; } - public virtual Expression VisitAtTimeZone([NotNull] AtTimeZoneExpression atTimeZoneExpression) + /// + /// Visits the children of an . + /// + /// The expression. + /// + /// An . + /// + [NotNull] + public virtual Expression VisitAtTimeZone([NotNull] AtTimeZoneExpression expression) { - Check.NotNull(atTimeZoneExpression, nameof(atTimeZoneExpression)); - - Visit(atTimeZoneExpression.TimestampExpression); + Visit(expression.Timestamp); Sql.Append(" AT TIME ZONE '"); - Sql.Append(atTimeZoneExpression.TimeZone); + Sql.Append(expression.TimeZone); Sql.Append('\''); - return atTimeZoneExpression; + return expression; } - public virtual Expression VisitILike([NotNull] ILikeExpression iLikeExpression) + /// + /// Visits the children of an . + /// + /// The expression. + /// + /// An . + /// + [NotNull] + public virtual Expression VisitILike([NotNull] ILikeExpression expression) { - Check.NotNull(iLikeExpression, nameof(iLikeExpression)); - //var parentTypeMapping = _typeMapping; - //_typeMapping = InferTypeMappingFromColumn(iLikeExpression.Match) ?? parentTypeMapping; + //_typeMapping = InferTypeMappingFromColumn(expression.Match) ?? parentTypeMapping; - Visit(iLikeExpression.Match); + Visit(expression.Match); Sql.Append(" ILIKE "); - Visit(iLikeExpression.Pattern); + Visit(expression.Pattern); - if (iLikeExpression.EscapeChar != null) + if (expression.EscapeChar != null) { Sql.Append(" ESCAPE "); - Visit(iLikeExpression.EscapeChar); + Visit(expression.EscapeChar); } //_typeMapping = parentTypeMapping; - return iLikeExpression; + return expression; } - public virtual Expression VisitExplicitStoreTypeCast([NotNull] ExplicitStoreTypeCastExpression castExpression) + /// + /// Visits the children of an . + /// + /// The expression. + /// + /// An . + /// + [NotNull] + public virtual Expression VisitExplicitStoreTypeCast([NotNull] ExplicitStoreTypeCastExpression expression) { Sql.Append("CAST("); //var parentTypeMapping = _typeMapping; - //_typeMapping = InferTypeMappingFromColumn(castExpression.Operand); + //_typeMapping = InferTypeMappingFromColumn(expression.Operand); - Visit(castExpression.Operand); + Visit(expression.Operand); Sql.Append(" AS ") - .Append(castExpression.StoreType) + .Append(expression.StoreType) .Append(")"); //_typeMapping = parentTypeMapping; - return castExpression; + return expression; } + /// + /// Visits the children of a . + /// + /// The expression. + /// + /// An . + /// + [NotNull] public virtual Expression VisitCustomBinary([NotNull] CustomBinaryExpression expression) { - Check.NotNull(expression, nameof(expression)); - Sql.Append('('); Visit(expression.Left); Sql.Append(' '); @@ -362,10 +396,16 @@ public virtual Expression VisitCustomBinary([NotNull] CustomBinaryExpression exp return expression; } + /// + /// Visits the children of a . + /// + /// The expression. + /// + /// An . + /// + [NotNull] public virtual Expression VisitCustomUnary([NotNull] CustomUnaryExpression expression) { - Check.NotNull(expression, nameof(expression)); - if (expression.Postfix) { Visit(expression.Operand); @@ -380,7 +420,15 @@ public virtual Expression VisitCustomUnary([NotNull] CustomUnaryExpression expre return expression; } - public virtual Expression VisitPgFunction([NotNull] PgFunctionExpression e) + /// + /// Visits the children of a . + /// + /// The expression. + /// + /// An . + /// + [NotNull] + public virtual Expression VisitPgFunction([NotNull] PgFunctionExpression expression) { //var parentTypeMapping = _typeMapping; @@ -388,15 +436,15 @@ public virtual Expression VisitPgFunction([NotNull] PgFunctionExpression e) var wroteSchema = false; - if (e.Instance != null) + if (expression.Instance != null) { - Visit(e.Instance); + Visit(expression.Instance); Sql.Append("."); } - else if (!string.IsNullOrWhiteSpace(e.Schema)) + else if (!string.IsNullOrWhiteSpace(expression.Schema)) { - Sql.Append(SqlGenerator.DelimitIdentifier(e.Schema)) + Sql.Append(SqlGenerator.DelimitIdentifier(expression.Schema)) .Append("."); wroteSchema = true; @@ -404,18 +452,18 @@ public virtual Expression VisitPgFunction([NotNull] PgFunctionExpression e) Sql.Append( wroteSchema - ? SqlGenerator.DelimitIdentifier(e.FunctionName) - : e.FunctionName); + ? SqlGenerator.DelimitIdentifier(expression.FunctionName) + : expression.FunctionName); Sql.Append("("); //_typeMapping = null; - GenerateList(e.PositionalArguments); + GenerateList(expression.PositionalArguments); - bool hasArguments = e.PositionalArguments.Count > 0 && e.NamedArguments.Count > 0; + bool hasArguments = expression.PositionalArguments.Count > 0 && expression.NamedArguments.Count > 0; - foreach (var kv in e.NamedArguments) + foreach (var kv in expression.NamedArguments) { if (hasArguments) Sql.Append(", "); @@ -431,7 +479,7 @@ public virtual Expression VisitPgFunction([NotNull] PgFunctionExpression e) Sql.Append(")"); //_typeMapping = parentTypeMapping; - return e; + return expression; } #endregion