From d60631b979d9846f31e964f0ea6502ccaf890d16 Mon Sep 17 00:00:00 2001 From: Austin Drenski Date: Sun, 22 Jul 2018 13:29:39 -0400 Subject: [PATCH] Add doc comments and refactor PgFunctionExpression (#531) Moving changes from 431. --- .../Internal/PgFunctionExpression.cs | 343 +++++++++--------- 1 file changed, 168 insertions(+), 175 deletions(-) diff --git a/src/EFCore.PG/Query/Expressions/Internal/PgFunctionExpression.cs b/src/EFCore.PG/Query/Expressions/Internal/PgFunctionExpression.cs index 0722af1e9..ccb1fc548 100644 --- a/src/EFCore.PG/Query/Expressions/Internal/PgFunctionExpression.cs +++ b/src/EFCore.PG/Query/Expressions/Internal/PgFunctionExpression.cs @@ -1,12 +1,36 @@ -using System; +#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.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Linq; using System.Linq.Expressions; +using System.Text; using JetBrains.Annotations; -using Microsoft.EntityFrameworkCore.Query.Expressions; -using Microsoft.EntityFrameworkCore.Query.Sql; using Npgsql.EntityFrameworkCore.PostgreSQL.Query.Sql.Internal; using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities; @@ -16,143 +40,197 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query.Expressions.Internal /// Represents a SQL function call expression, supporting PostgreSQL's named parameter notation. /// [DebuggerDisplay("{" + nameof(ToString) + "()}")] - public class PgFunctionExpression : Expression + public class PgFunctionExpression : Expression, IEquatable { - readonly ReadOnlyCollection _positionalArguments; - readonly ReadOnlyDictionary _namedArguments; - - static readonly ReadOnlyDictionary EmptyNamedArguments = + /// + /// An empty instance of . + /// + [NotNull] static readonly ReadOnlyDictionary EmptyNamedArguments = new ReadOnlyDictionary(new Dictionary()); - //new ReadOnlyDictionaryDictionary(); /// - /// Initializes a new instance of the class. + /// The backing field for . + /// + [NotNull] [ItemNotNull] readonly ReadOnlyCollection _positionalArguments; + + /// + /// The backing field for . + /// + [NotNull] readonly ReadOnlyDictionary _namedArguments; + + /// + /// Gets the name of the function. + /// + /// + /// The name of the function. + /// + [NotNull] + public virtual string FunctionName { get; } + + /// + /// Gets the name of the schema. + /// + /// + /// The name of the schema. + /// + [CanBeNull] + public virtual string Schema { get; } + + /// + /// The instance. + /// + [CanBeNull] + public virtual Expression Instance { get; } + + /// + /// The positional arguments. + /// + [NotNull] + [ItemNotNull] + public virtual IReadOnlyList PositionalArguments => _positionalArguments; + + /// + /// The named arguments. /// - /// Name of the function. - /// The return type. + [NotNull] + public virtual IReadOnlyDictionary NamedArguments => _namedArguments; + + /// + public override ExpressionType NodeType => ExpressionType.Extension; + + /// + public override Type Type { get; } + + /// + /// Initializes a new instance of the class. + /// + /// Name of the function. + /// The return type. public PgFunctionExpression( [NotNull] string functionName, [NotNull] Type returnType) : this( - Check.NotEmpty(functionName, nameof(functionName)), - Check.NotNull(returnType, nameof(returnType)), - Enumerable.Empty()) - { - } + instance: null, + Check.NotEmpty(functionName, nameof(functionName)), + schema: null, + Check.NotNull(returnType, nameof(returnType)), + Enumerable.Empty(), + EmptyNamedArguments) {} /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// Name of the function. - /// The return type. - /// The positional arguments. + /// Name of the function. + /// The return type. + /// The positional arguments. public PgFunctionExpression( [NotNull] string functionName, [NotNull] Type returnType, [NotNull] IEnumerable positionalArguments) : this( - Check.NotEmpty(functionName, nameof(functionName)), - Check.NotNull(returnType, nameof(returnType)), - /*schema*/ null, - Check.NotNull(positionalArguments, nameof(positionalArguments))) - { - } + instance: null, + Check.NotEmpty(functionName, nameof(functionName)), + schema: null, + Check.NotNull(returnType, nameof(returnType)), + Check.NotNull(positionalArguments, nameof(positionalArguments)), + EmptyNamedArguments) {} /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// Name of the function. - /// The return type. - /// The namedarguments. + /// Name of the function. + /// The return type. + /// The namedarguments. public PgFunctionExpression( [NotNull] string functionName, [NotNull] Type returnType, - [NotNull] IDictionary namedArguments) + [NotNull] IDictionary namedArguments) : this( - /*instance*/ null, + instance: null, Check.NotEmpty(functionName, nameof(functionName)), - /*schema*/ null, + schema: null, Check.NotNull(returnType, nameof(returnType)), Enumerable.Empty(), - namedArguments) - { - } + namedArguments) {} /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// Name of the function. - /// The schema this function exists in if any. - /// The return type. - /// The positional arguments. + /// Name of the function. + /// The schema this function exists in if any. + /// The return type. + /// The positional arguments. public PgFunctionExpression( [NotNull] string functionName, [NotNull] Type returnType, [CanBeNull] string schema, [NotNull] IEnumerable positionalArguments) : this( - /*instance*/ null, + instance: null, Check.NotEmpty(functionName, nameof(functionName)), schema, Check.NotNull(returnType, nameof(returnType)), Check.NotNull(positionalArguments, nameof(positionalArguments)), - EmptyNamedArguments) - { - } + EmptyNamedArguments) {} /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// The instance on which the function is called. - /// Name of the function. - /// The return type. - /// The positional arguments. + /// The instance on which the function is called. + /// Name of the function. + /// The return type. + /// The positional arguments. public PgFunctionExpression( [NotNull] Expression instance, [NotNull] string functionName, [NotNull] Type returnType, [NotNull] IEnumerable positionalArguments) : this( - Check.NotNull(instance, nameof(instance)), - Check.NotEmpty(functionName, nameof(functionName)), - /*schema*/ null, - Check.NotNull(returnType, nameof(returnType)), - Check.NotNull(positionalArguments, nameof(positionalArguments)), - EmptyNamedArguments) - { - } + Check.NotNull(instance, nameof(instance)), + Check.NotEmpty(functionName, nameof(functionName)), + schema: null, + Check.NotNull(returnType, nameof(returnType)), + Check.NotNull(positionalArguments, nameof(positionalArguments)), + EmptyNamedArguments) {} /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// The instance on which the function is called. - /// Name of the function. - /// The return type. - /// The positional arguments. - /// The named arguments. + /// The instance on which the function is called. + /// Name of the function. + /// The return type. + /// The positional arguments. + /// The named arguments. public PgFunctionExpression( [NotNull] Expression instance, [NotNull] string functionName, [NotNull] Type returnType, [NotNull] IEnumerable positionalArguments, - [NotNull] IDictionary namedArguments) + [NotNull] IDictionary namedArguments) : this( Check.NotNull(instance, nameof(instance)), Check.NotEmpty(functionName, nameof(functionName)), - /*schema*/ null, + schema: null, Check.NotNull(returnType, nameof(returnType)), Check.NotNull(positionalArguments, nameof(positionalArguments)), - namedArguments) - { - } + namedArguments) {} - PgFunctionExpression( + /// + /// Initializes a new instance of the class. + /// + /// The instance on which the function is called. + /// Name of the function. + /// The schema this function exists in if any. + /// The return type. + /// The positional arguments. + /// The named arguments. + internal PgFunctionExpression( [CanBeNull] Expression instance, [NotNull] string functionName, [CanBeNull] string schema, [NotNull] Type returnType, [NotNull] IEnumerable positionalArguments, - [NotNull] IDictionary namedArguments) + [NotNull] IDictionary namedArguments) { Instance = instance; FunctionName = functionName; @@ -162,52 +240,7 @@ public PgFunctionExpression( _namedArguments = new ReadOnlyDictionary(namedArguments); } - /// - /// Gets the name of the function. - /// - /// - /// The name of the function. - /// - public virtual string FunctionName { get; } - - /// - /// Gets the name of the schema. - /// - /// - /// The name of the schema. - /// - public virtual string Schema { get; } - - /// - /// The instance. - /// - public virtual Expression Instance { get; } - - /// - /// The positional arguments. - /// - public virtual IReadOnlyList PositionalArguments => _positionalArguments; - - /// - /// The named arguments. - /// - public virtual IReadOnlyDictionary NamedArguments => _namedArguments; - - /// - /// 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 that represents the static type of the expression. - public override Type Type { get; } - - /// - /// Dispatches to the specific visit method for this node type. - /// + /// protected override Expression Accept(ExpressionVisitor visitor) { Check.NotNull(visitor, nameof(visitor)); @@ -217,25 +250,13 @@ protected override Expression Accept(ExpressionVisitor visitor) : 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 newInstance = Instance != null ? visitor.Visit(Instance) : null; + var newInstance = visitor.Visit(Instance); var newPositionalArguments = visitor.VisitAndConvert(_positionalArguments, nameof(VisitChildren)); - var newNamedArguments = new Dictionary(); + var newNamedArguments = new Dictionary(_namedArguments.Count); var namedArgumentsChanged = false; foreach (var kv in _namedArguments) { @@ -252,53 +273,28 @@ protected override Expression VisitChildren(ExpressionVisitor visitor) : 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; - } - - if (ReferenceEquals(this, obj)) - { - return true; - } - - return obj.GetType() == GetType() && Equals((PgFunctionExpression)obj); - } + /// + public override bool Equals(object obj) => obj is PgFunctionExpression pgFunction && Equals(pgFunction); - bool Equals(PgFunctionExpression other) - => Type == other.Type + /// + public bool Equals(PgFunctionExpression other) + => other != null + && Type == other.Type && string.Equals(FunctionName, other.FunctionName) && string.Equals(Schema, other.Schema) && _positionalArguments.SequenceEqual(other._positionalArguments) && _namedArguments.Count == other._namedArguments.Count - && _namedArguments.All(kv => other._namedArguments.TryGetValue(kv.Key, out var otherValue) && kv.Value.Equals(otherValue)) - && (Instance == null && other.Instance == null - || Instance?.Equals(other.Instance) == true); - + && _namedArguments.All(kv => other._namedArguments.TryGetValue(kv.Key, out var otherValue) && kv.Value?.Equals(otherValue) == true) + && (Instance == null && other.Instance == null || Instance?.Equals(other.Instance) == true); - - /// - /// Returns a hash code for this object. - /// - /// - /// A hash code for this object. - /// + /// public override int GetHashCode() { unchecked { var hashCode = _positionalArguments.Aggregate(0, (current, argument) => current + ((current * 397) ^ argument.GetHashCode())); hashCode = (hashCode * 397) ^ _namedArguments.Aggregate(0, (current, argument) => - current + ((current * 397) ^ argument.Key.GetHashCode()) + ((current * 397) ^ argument.Value.GetHashCode())); + current + ((current * 397) ^ argument.Key.GetHashCode()) + ((current * 397) ^ argument.Value.GetHashCode())); hashCode = (hashCode * 397) ^ (Instance?.GetHashCode() ?? 0); hashCode = (hashCode * 397) ^ FunctionName.GetHashCode(); hashCode = (hashCode * 397) ^ (Schema?.GetHashCode() ?? 0); @@ -307,14 +303,11 @@ public override int GetHashCode() } } - /// - /// Creates a representation of the Expression. - /// - /// A representation of the Expression. + /// public override string ToString() => (Instance != null ? Instance + "." : Schema != null ? Schema + "." : "") + - $"{FunctionName}({string.Join("", "", PositionalArguments)}" + - (NamedArguments.Count > 0 ? ", " + (string.Join("", "", NamedArguments.Select(a => $"{a.Key} => {a.Value}"))) : "") + - ")"; + $"{FunctionName}({string.Join("", "", PositionalArguments)}" + + (NamedArguments.Count > 0 ? ", " + string.Join("", "", NamedArguments.Select(a => $"{a.Key} => {a.Value}")) : "") + + ")"; } }