protected override Expression VisitExtension(Expression extensionExpression)
        {
            Check.NotNull(extensionExpression, nameof(extensionExpression));

            if (extensionExpression is ShapedQueryExpression shapedQueryExpression)
            {
                return(shapedQueryExpression.Update(Visit(shapedQueryExpression.QueryExpression), shapedQueryExpression.ShaperExpression));
            }

            // Only applies to 'CASE WHEN condition...' not 'CASE operand WHEN...'
            if (extensionExpression is CaseExpression caseExpression &&
                caseExpression.Operand == null &&
                caseExpression.ElseResult is CaseExpression nestedCaseExpression &&
                nestedCaseExpression.Operand == null)
            {
                return(VisitExtension(
                           _sqlExpressionFactory.Case(
                               caseExpression.WhenClauses.Union(nestedCaseExpression.WhenClauses).ToList(),
                               nestedCaseExpression.ElseResult)));
            }

            if (extensionExpression is SqlBinaryExpression sqlBinaryExpression)
            {
                return(SimplifySqlBinary(sqlBinaryExpression));
            }

            return(base.VisitExtension(extensionExpression));
        }
Пример #2
0
        /// <summary>
        ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
        ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
        ///     any release. You should only use it directly in your code with extreme caution and knowing that
        ///     doing so can result in application failures when updating to a new Entity Framework Core release.
        /// </summary>
        public virtual SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType, IDiagnosticsLogger <DbLoggerCategory.Query> logger)
        {
            Check.NotNull(member, nameof(member));
            Check.NotNull(returnType, nameof(returnType));
            Check.NotNull(logger, nameof(logger));

            if (_memberToFunctionName.TryGetValue(member, out var functionName))
            {
                return(returnType == typeof(bool)
                    ? _sqlExpressionFactory.Case(
                           new[]
                {
                    new CaseWhenClause(
                        _sqlExpressionFactory.IsNotNull(instance),
                        _sqlExpressionFactory.Function(
                            functionName,
                            new[] { instance },
                            nullable: false,
                            argumentsPropagateNullability: new[] { false },
                            returnType))
                },
                           null)
                    : (SqlExpression)_sqlExpressionFactory.Function(
                           functionName,
                           new[] { instance },
                           nullable: true,
                           argumentsPropagateNullability: new[] { true },
                           returnType));
            }

            return(null);
        }
        public virtual SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType)
        {
            Check.NotNull(member, nameof(member));
            Check.NotNull(returnType, nameof(returnType));

            if (_memberToFunctionName.TryGetValue(member, out var functionName))
            {
                SqlExpression translation = _sqlExpressionFactory.Function(
                    functionName, new[] { instance }, returnType);

                if (returnType == typeof(bool))
                {
                    translation = _sqlExpressionFactory.Case(
                        new[]
                    {
                        new CaseWhenClause(
                            _sqlExpressionFactory.IsNotNull(instance),
                            translation)
                    },
                        null);
                }

                return(translation);
            }

            return(null);
        }
 // If the distance should be calculated, use `ST_Distance_Sphere()` for SRID 4326 and
 // `ST_Distance()` for all other cases.
 private SqlExpression GetDistanceCallBySrid(
     SqlExpression left,
     SqlExpression right,
     Type resultType,
     RelationalTypeMapping resultTypeMapping)
 {
     return(_sqlExpressionFactory.Case(
                new[]
     {
         new CaseWhenClause(
             _sqlExpressionFactory.Equal(
                 _sqlExpressionFactory.Function(
                     "ST_SRID",
                     new[] { left },
                     typeof(int),
                     _typeMappingSource.FindMapping(typeof(int))),
                 _sqlExpressionFactory.Constant(4326)),
             MySqlSpatialDbFunctionsExtensionsMethodTranslator.GetStDistanceSphereFunctionCall(
                 left,
                 right,
                 SpatialDistanceAlgorithm.Native,
                 resultType,
                 resultTypeMapping,
                 _sqlExpressionFactory,
                 _options)),
     },
                MySqlSpatialDbFunctionsExtensionsMethodTranslator.GetStDistanceFunctionCall(
                    left,
                    right,
                    resultType,
                    resultTypeMapping,
                    _sqlExpressionFactory)));
 }
Пример #5
0
        /// <summary>
        ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
        ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
        ///     any release. You should only use it directly in your code with extreme caution and knowing that
        ///     doing so can result in application failures when updating to a new Entity Framework Core release.
        /// </summary>
        public virtual SqlExpression?Translate(
            SqlExpression?instance,
            MemberInfo member,
            Type returnType,
            IDiagnosticsLogger <DbLoggerCategory.Query> logger)
        {
            Check.NotNull(member, nameof(member));
            Check.NotNull(returnType, nameof(returnType));
            Check.NotNull(logger, nameof(logger));

            if (Equals(member, _isClosed) &&
                instance != null)
            {
                return(_sqlExpressionFactory.Case(
                           new[]
                {
                    new CaseWhenClause(
                        _sqlExpressionFactory.IsNotNull(instance),
                        _sqlExpressionFactory.Function(
                            "IsClosed",
                            new[] { instance },
                            nullable: false,
                            argumentsPropagateNullability: new[] { false },
                            returnType))
                },
                           null));
            }

            return(null);
        }
    private SqlExpression TranslateIndexOf(
        SqlExpression instance,
        MethodInfo method,
        SqlExpression searchExpression,
        SqlExpression?startIndex)
    {
        var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, searchExpression) !;

        searchExpression = _sqlExpressionFactory.ApplyTypeMapping(searchExpression, stringTypeMapping);
        instance         = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping);

        var charIndexArguments = new List <SqlExpression> {
            searchExpression, instance
        };

        if (startIndex is not null)
        {
            charIndexArguments.Add(_sqlExpressionFactory.Add(startIndex, _sqlExpressionFactory.Constant(1)));
        }

        var argumentsPropagateNullability = Enumerable.Repeat(true, charIndexArguments.Count);

        SqlExpression charIndexExpression;
        var           storeType = stringTypeMapping.StoreType;

        if (string.Equals(storeType, "nvarchar(max)", StringComparison.OrdinalIgnoreCase) ||
            string.Equals(storeType, "varchar(max)", StringComparison.OrdinalIgnoreCase))
        {
            charIndexExpression = _sqlExpressionFactory.Function(
                "CHARINDEX",
                charIndexArguments,
                nullable: true,
                argumentsPropagateNullability,
                typeof(long));

            charIndexExpression = _sqlExpressionFactory.Convert(charIndexExpression, typeof(int));
        }
        else
        {
            charIndexExpression = _sqlExpressionFactory.Function(
                "CHARINDEX",
                charIndexArguments,
                nullable: true,
                argumentsPropagateNullability,
                method.ReturnType);
        }

        charIndexExpression = _sqlExpressionFactory.Subtract(charIndexExpression, _sqlExpressionFactory.Constant(1));

        return(_sqlExpressionFactory.Case(
                   new[]
        {
            new CaseWhenClause(
                _sqlExpressionFactory.Equal(
                    searchExpression,
                    _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)),
                _sqlExpressionFactory.Constant(0))
        },
                   charIndexExpression));
    }
Пример #7
0
        public virtual SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType)
        {
            if (Equals(member, _isClosed))
            {
                SqlExpression sqlExpression = _sqlExpressionFactory.Function(
                    "ST_IsClosed",
                    new [] { instance },
                    returnType);

                // ST_IsRing and others returns TRUE for a NULL value in MariaDB, which is inconsistent with NTS' implementation.
                // We return the following instead:
                // CASE
                //     WHEN instance IS NULL THEN NULL
                //     ELSE expression
                // END
                if (returnType == typeof(bool))
                {
                    sqlExpression = _sqlExpressionFactory.Case(
                        new[]
                    {
                        new CaseWhenClause(
                            _sqlExpressionFactory.IsNull(instance),
                            _sqlExpressionFactory.Constant(null, RelationalTypeMapping.NullMapping))
                    },
                        sqlExpression);
                }

                return(sqlExpression);
            }

            return(null);
        }
        public virtual SqlExpression Translate(
            SqlExpression instance,
            MethodInfo method,
            IReadOnlyList <SqlExpression> arguments,
            IDiagnosticsLogger <DbLoggerCategory.Query> logger)
        {
            if (instance == null ||
                method.Name != nameof(ToString) ||
                arguments.Count != 0)
            {
                return(null);
            }

            if (instance.Type == typeof(bool))
            {
                return(instance is ColumnExpression columnExpression &&
                       columnExpression.IsNullable
                    ? _sqlExpressionFactory.Case(
                           new[]
                {
                    new CaseWhenClause(
                        _sqlExpressionFactory.Equal(instance, _sqlExpressionFactory.Constant(false)),
                        _sqlExpressionFactory.Constant(false.ToString())),
                    new CaseWhenClause(
                        _sqlExpressionFactory.Equal(instance, _sqlExpressionFactory.Constant(true)),
                        _sqlExpressionFactory.Constant(true.ToString()))
                },
                           _sqlExpressionFactory.Constant(null))
                    : _sqlExpressionFactory.Case(
                           new[]
                {
                    new CaseWhenClause(
                        _sqlExpressionFactory.Equal(instance, _sqlExpressionFactory.Constant(false)),
                        _sqlExpressionFactory.Constant(false.ToString()))
                },
                           _sqlExpressionFactory.Constant(true.ToString())));
            }

            // Translates parameterless Object.ToString() calls.
            return(_supportedTypes.Contains(instance.Type.UnwrapNullableType())
                ? _sqlExpressionFactory.Convert(instance, typeof(string))
                : null);
        }
    /// <summary>
    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
    ///     any release. You should only use it directly in your code with extreme caution and knowing that
    ///     doing so can result in application failures when updating to a new Entity Framework Core release.
    /// </summary>
    protected override Expression VisitExtension(Expression extensionExpression)
    {
        if (extensionExpression is ShapedQueryExpression shapedQueryExpression)
        {
            return(shapedQueryExpression.Update(Visit(shapedQueryExpression.QueryExpression), shapedQueryExpression.ShaperExpression));
        }

        // Only applies to 'CASE WHEN condition...' not 'CASE operand WHEN...'
        if (extensionExpression is CaseExpression caseExpression &&
            caseExpression.Operand == null &&
            caseExpression.ElseResult is CaseExpression nestedCaseExpression &&
            nestedCaseExpression.Operand == null)
        {
            return(VisitExtension(
                       _sqlExpressionFactory.Case(
                           caseExpression.WhenClauses.Union(nestedCaseExpression.WhenClauses).ToList(),
                           nestedCaseExpression.ElseResult)));
        }

        if (extensionExpression is SqlBinaryExpression sqlBinaryExpression)
        {
            return(SimplifySqlBinary(sqlBinaryExpression));
        }

        if (extensionExpression is SqlFunctionExpression sqlFunctionExpression &&
            IsCoalesce(sqlFunctionExpression))
        {
            var arguments = new List <SqlExpression>();
            foreach (var argument in sqlFunctionExpression.Arguments !)
            {
                var newArgument = (SqlExpression)Visit(argument);
                if (IsCoalesce(newArgument))
                {
                    arguments.AddRange(((SqlFunctionExpression)newArgument).Arguments !);
                }
                else
                {
                    arguments.Add(newArgument);
                }
            }

            var distinctArguments = arguments.Distinct().ToList();

            return(distinctArguments.Count > 1
                ? new SqlFunctionExpression(
                       sqlFunctionExpression.Name,
                       distinctArguments,
                       sqlFunctionExpression.IsNullable,
                       argumentsPropagateNullability: distinctArguments.Select(_ => false).ToArray(),
                       sqlFunctionExpression.Type,
                       sqlFunctionExpression.TypeMapping)
                : distinctArguments[0]);
        }

        return(base.VisitExtension(extensionExpression));
Пример #10
0
        public virtual SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType)
        {
            if (_memberToFunctionName.TryGetValue(member, out var functionName))
            {
                Debug.Assert(instance.TypeMapping != null, "Instance must have typeMapping assigned.");
                var storeType = instance.TypeMapping.StoreType;

                var resultTypeMapping = typeof(Geometry).IsAssignableFrom(returnType)
                    ? _typeMappingSource.FindMapping(returnType, storeType)
                    : _typeMappingSource.FindMapping(returnType);

                // Emulate ST_IsRing if not supported.
                var sqlExpression = functionName != "ST_IsRing" ||
                                    _options.ServerVersion.SupportsSpatialIsRingFunction
                    ? (SqlExpression)_sqlExpressionFactory.Function(
                    functionName,
                    new[] { instance },
                    returnType,
                    resultTypeMapping)
                    : _sqlExpressionFactory.AndAlso(
                    _sqlExpressionFactory.Function(
                        "ST_IsClosed",
                        new[] { instance },
                        returnType,
                        resultTypeMapping),
                    _sqlExpressionFactory.Function(
                        "ST_IsSimple",
                        new[] { instance },
                        returnType,
                        resultTypeMapping)
                    );

                // ST_IsRing and others returns TRUE for a NULL value in MariaDB, which is inconsistent with NTS' implementation.
                // We return the following instead:
                // CASE
                //     WHEN instance IS NULL THEN NULL
                //     ELSE expression
                // END
                if (returnType == typeof(bool))
                {
                    sqlExpression = _sqlExpressionFactory.Case(
                        new[]
                    {
                        new CaseWhenClause(
                            _sqlExpressionFactory.IsNull(instance),
                            _sqlExpressionFactory.Constant(null, RelationalTypeMapping.NullMapping))
                    },
                        sqlExpression);
                }

                return(sqlExpression);
            }

            return(null);
        }
 private SqlExpression ConvertToValue(SqlExpression sqlExpression, bool condition)
 => condition
         ? _sqlExpressionFactory.Case(
     new[]
 {
     new CaseWhenClause(
         SimplifyNegatedBinary(sqlExpression),
         _sqlExpressionFactory.ApplyDefaultTypeMapping(_sqlExpressionFactory.Constant(true)))
 },
     _sqlExpressionFactory.Constant(false))
         : sqlExpression;
 private Expression ConvertToValue(SqlExpression sqlExpression, bool condition)
 {
     return(condition
         ? _sqlExpressionFactory.Case(new[]
     {
         new CaseWhenClause(
             sqlExpression,
             _sqlExpressionFactory.ApplyDefaultTypeMapping(_sqlExpressionFactory.Constant(true)))
     },
                                      _sqlExpressionFactory.Constant(false))
         : sqlExpression);
 }
Пример #13
0
        protected override Expression VisitConditional(ConditionalExpression conditionalExpression)
        {
            Check.NotNull(conditionalExpression, nameof(conditionalExpression));

            var test    = Visit(conditionalExpression.Test);
            var ifTrue  = Visit(conditionalExpression.IfTrue);
            var ifFalse = Visit(conditionalExpression.IfFalse);

            return(TranslationFailed(conditionalExpression.Test, test, out var sqlTest) ||
                   TranslationFailed(conditionalExpression.IfTrue, ifTrue, out var sqlIfTrue) ||
                   TranslationFailed(conditionalExpression.IfFalse, ifFalse, out var sqlIfFalse)
                ? null
                : _sqlExpressionFactory.Case(new[] { new CaseWhenClause(sqlTest, sqlIfTrue) }, sqlIfFalse));
        }
Пример #14
0
 protected override Expression VisitExtension(Expression node)
 {
     // Only applies to 'CASE WHEN condition...' not 'CASE operand WHEN...'
     if (node is CaseExpression caseExpression && caseExpression.Operand == null)
     {
         if (caseExpression.ElseResult is CaseExpression nestedCaseExpression && nestedCaseExpression.Operand == null)
         {
             return(VisitExtension(_sqlExpressionFactory.Case(
                                       caseExpression.WhenClauses.Union(nestedCaseExpression.WhenClauses).ToList(),
                                       nestedCaseExpression.ElseResult)));
         }
     }
     return(base.VisitExtension(node));
 }
Пример #15
0
        /// <summary>
        ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
        ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
        ///     any release. You should only use it directly in your code with extreme caution and knowing that
        ///     doing so can result in application failures when updating to a new Entity Framework Core release.
        /// </summary>
        public virtual SqlExpression?Translate(
            SqlExpression?instance,
            MethodInfo method,
            IReadOnlyList <SqlExpression> arguments,
            IDiagnosticsLogger <DbLoggerCategory.Query> logger)
        {
            Check.NotNull(method, nameof(method));
            Check.NotNull(arguments, nameof(arguments));
            Check.NotNull(logger, nameof(logger));

            if (method.ReturnType == typeof(int))
            {
                SqlExpression?left  = null;
                SqlExpression?right = null;
                if (method.Name == nameof(string.Compare) &&
                    arguments.Count == 2 &&
                    arguments[0].Type == arguments[1].Type)
                {
                    left  = arguments[0];
                    right = arguments[1];
                }
                else if (method.Name == nameof(string.CompareTo) &&
                         arguments.Count == 1 &&
                         instance != null &&
                         instance.Type == arguments[0].Type)
                {
                    left  = instance;
                    right = arguments[0];
                }

                if (left != null &&
                    right != null)
                {
                    return(_sqlExpressionFactory.Case(
                               new[]
                    {
                        new CaseWhenClause(
                            _sqlExpressionFactory.Equal(left, right), _sqlExpressionFactory.Constant(0)),
                        new CaseWhenClause(
                            _sqlExpressionFactory.GreaterThan(left, right), _sqlExpressionFactory.Constant(1)),
                        new CaseWhenClause(
                            _sqlExpressionFactory.LessThan(left, right), _sqlExpressionFactory.Constant(-1))
                    },
                               null));
                }
            }

            return(null);
        }
Пример #16
0
        public SqlExpression Translate(SqlExpression instance, MethodInfo method, IList <SqlExpression> arguments)
        {
            method = method.OnInterface(typeof(IGeometry));
            if (_methodToFunctionName.TryGetValue(method, out var functionName))
            {
                SqlExpression translation = _sqlExpressionFactory.Function(
                    functionName,
                    new[] { instance }.Concat(arguments),
                    method.ReturnType);

                if (method.ReturnType == typeof(bool))
                {
                    translation = _sqlExpressionFactory.Case(
                        new[]
                    {
                        new CaseWhenClause(_sqlExpressionFactory.IsNotNull(instance), translation)
                    },
                        null);
                }

                return(translation);
            }

            if (Equals(method, _getGeometryN))
            {
                return(_sqlExpressionFactory.Function(
                           "GeometryN",
                           new[] {
                    instance,
                    _sqlExpressionFactory.Add(
                        arguments[0],
                        _sqlExpressionFactory.Constant(1))
                },
                           method.ReturnType));
            }

            if (Equals(method, _isWithinDistance))
            {
                return(_sqlExpressionFactory.LessThanOrEqual(
                           _sqlExpressionFactory.Function(
                               "Distance",
                               new[] { instance, arguments[0] },
                               typeof(double)),
                           arguments[1]));
            }

            return(null);
        }
Пример #17
0
        public virtual SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType)
        {
            if (Equals(member, _isClosed))
            {
                return(_sqlExpressionFactory.Case(
                           new[] {
                    new CaseWhenClause(
                        _sqlExpressionFactory.IsNotNull(instance),
                        _sqlExpressionFactory.Function(
                            "IsClosed",
                            new[] { instance },
                            returnType))
                },
                           null));
            }

            return(null);
        }
        protected override Expression VisitConditional(ConditionalExpression conditionalExpression)
        {
            var test    = (SqlExpression)Visit(conditionalExpression.Test);
            var ifTrue  = (SqlExpression)Visit(conditionalExpression.IfTrue);
            var ifFalse = (SqlExpression)Visit(conditionalExpression.IfFalse);

            if (TranslationFailed(conditionalExpression.Test, test) ||
                TranslationFailed(conditionalExpression.IfTrue, ifTrue) ||
                TranslationFailed(conditionalExpression.IfFalse, ifFalse))
            {
                return(null);
            }

            return(_sqlExpressionFactory.Case(
                       new[]
            {
                new CaseWhenClause(test, ifTrue)
            },
                       ifFalse));
        }
        public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments)
        {
            if (method.ReturnType == typeof(int))
            {
                SqlExpression left  = null;
                SqlExpression right = null;
                if (method.Name == nameof(string.Compare) &&
                    arguments.Count == 2 &&
                    arguments[0].Type.UnwrapNullableType() == arguments[1].Type.UnwrapNullableType())
                {
                    left  = arguments[0];
                    right = arguments[1];
                }
                else if (method.Name == nameof(string.CompareTo) &&
                         arguments.Count == 1 &&
                         instance != null &&
                         instance.Type.UnwrapNullableType() == arguments[0].Type.UnwrapNullableType())
                {
                    left  = instance;
                    right = arguments[0];
                }

                if (left != null &&
                    right != null)
                {
                    return(_sqlExpressionFactory.Case(
                               new[]
                    {
                        new CaseWhenClause(
                            _sqlExpressionFactory.Equal(left, right), _sqlExpressionFactory.Constant(0)),
                        new CaseWhenClause(
                            _sqlExpressionFactory.GreaterThan(left, right), _sqlExpressionFactory.Constant(1)),
                        new CaseWhenClause(
                            _sqlExpressionFactory.LessThan(left, right), _sqlExpressionFactory.Constant(-1))
                    },
                               null));
                }
            }

            return(null);
        }
Пример #20
0
        /// <summary>
        ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
        ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
        ///     any release. You should only use it directly in your code with extreme caution and knowing that
        ///     doing so can result in application failures when updating to a new Entity Framework Core release.
        /// </summary>
        public virtual SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType)
        {
            Check.NotNull(member, nameof(member));
            Check.NotNull(returnType, nameof(returnType));

            if (Equals(member, _isClosed))
            {
                return(_sqlExpressionFactory.Case(
                           new[]
                {
                    new CaseWhenClause(
                        _sqlExpressionFactory.IsNotNull(instance),
                        _sqlExpressionFactory.Function(
                            "IsClosed",
                            new[] { instance },
                            nullable: false,
                            argumentsPropagateNullability: new[] { false },
                            returnType))
                },
                           null));
            }

            return(null);
        }
        public SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType)
        {
            if (_memberToFunctionName.TryGetValue(member.OnInterface(typeof(ICurve)), out var functionName))
            {
                SqlExpression translation = _sqlExpressionFactory.Function(
                    functionName, new[] { instance }, returnType);

                if (returnType == typeof(bool))
                {
                    translation = _sqlExpressionFactory.Case(
                        new[]
                    {
                        new CaseWhenClause(
                            _sqlExpressionFactory.IsNotNull(instance),
                            translation)
                    },
                        null);
                }

                return(translation);
            }

            return(null);
        }
Пример #22
0
        /// <summary>
        ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
        ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
        ///     any release. You should only use it directly in your code with extreme caution and knowing that
        ///     doing so can result in application failures when updating to a new Entity Framework Core release.
        /// </summary>
        public virtual SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType)
        {
            Check.NotNull(member, nameof(member));
            Check.NotNull(returnType, nameof(returnType));

            if (_memberToFunctionName.TryGetValue(member, out var functionName))
            {
                return(returnType == typeof(bool)
                    ? _sqlExpressionFactory.Case(
                           new[]
                {
                    new CaseWhenClause(
                        _sqlExpressionFactory.IsNotNull(instance),
                        _sqlExpressionFactory.Function(
                            functionName,
                            new[] { instance },
                            nullable: false,
                            argumentsPropagateNullability: new[] { false },
                            returnType))
                },
                           null)
                    : (SqlExpression)_sqlExpressionFactory.Function(
                           functionName,
                           new[] { instance },
                           nullable: true,
                           argumentsPropagateNullability: new[] { true },
                           returnType));
            }

            if (Equals(member, _geometryType))
            {
                return(_sqlExpressionFactory.Case(
                           _sqlExpressionFactory.Function(
                               "rtrim",
                               new SqlExpression[]
                {
                    _sqlExpressionFactory.Function(
                        "GeometryType",
                        new[] { instance },
                        nullable: true,
                        argumentsPropagateNullability: new[] { true },
                        returnType),
                    _sqlExpressionFactory.Constant(" ZM")
                },
                               nullable: true,
                               argumentsPropagateNullability: new[] { true },
                               returnType),
                           new[] {
                    new CaseWhenClause(_sqlExpressionFactory.Constant("POINT"), _sqlExpressionFactory.Constant("Point")),
                    new CaseWhenClause(_sqlExpressionFactory.Constant("LINESTRING"), _sqlExpressionFactory.Constant("LineString")),
                    new CaseWhenClause(_sqlExpressionFactory.Constant("POLYGON"), _sqlExpressionFactory.Constant("Polygon")),
                    new CaseWhenClause(_sqlExpressionFactory.Constant("MULTIPOINT"), _sqlExpressionFactory.Constant("MultiPoint")),
                    new CaseWhenClause(
                        _sqlExpressionFactory.Constant("MULTILINESTRING"), _sqlExpressionFactory.Constant("MultiLineString")),
                    new CaseWhenClause(_sqlExpressionFactory.Constant("MULTIPOLYGON"), _sqlExpressionFactory.Constant("MultiPolygon")),
                    new CaseWhenClause(
                        _sqlExpressionFactory.Constant("GEOMETRYCOLLECTION"), _sqlExpressionFactory.Constant("GeometryCollection"))
                },
                           null));
            }

            if (Equals(member, _ogcGeometryType))
            {
                return(_sqlExpressionFactory.Case(
                           _sqlExpressionFactory.Function(
                               "rtrim",
                               new SqlExpression[]
                {
                    _sqlExpressionFactory.Function(
                        "GeometryType",
                        new[] { instance },
                        nullable: true,
                        argumentsPropagateNullability: new[] { true },
                        typeof(string)),
                    _sqlExpressionFactory.Constant(" ZM")
                },
                               nullable: true,
                               argumentsPropagateNullability: new[] { true },
                               typeof(string)),
                           new[] {
                    new CaseWhenClause(_sqlExpressionFactory.Constant("POINT"), _sqlExpressionFactory.Constant(OgcGeometryType.Point)),
                    new CaseWhenClause(
                        _sqlExpressionFactory.Constant("LINESTRING"), _sqlExpressionFactory.Constant(OgcGeometryType.LineString)),
                    new CaseWhenClause(_sqlExpressionFactory.Constant("POLYGON"), _sqlExpressionFactory.Constant(OgcGeometryType.Polygon)),
                    new CaseWhenClause(
                        _sqlExpressionFactory.Constant("MULTIPOINT"), _sqlExpressionFactory.Constant(OgcGeometryType.MultiPoint)),
                    new CaseWhenClause(
                        _sqlExpressionFactory.Constant("MULTILINESTRING"), _sqlExpressionFactory.Constant(OgcGeometryType.MultiLineString)),
                    new CaseWhenClause(
                        _sqlExpressionFactory.Constant("MULTIPOLYGON"), _sqlExpressionFactory.Constant(OgcGeometryType.MultiPolygon)),
                    new CaseWhenClause(
                        _sqlExpressionFactory.Constant("GEOMETRYCOLLECTION"),
                        _sqlExpressionFactory.Constant(OgcGeometryType.GeometryCollection))
                },
                           null));
            }

            return(null);
        }
    /// <summary>
    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
    ///     any release. You should only use it directly in your code with extreme caution and knowing that
    ///     doing so can result in application failures when updating to a new Entity Framework Core release.
    /// </summary>
    public virtual SqlExpression?Translate(
        SqlExpression?instance,
        MethodInfo method,
        IReadOnlyList <SqlExpression> arguments,
        IDiagnosticsLogger <DbLoggerCategory.Query> logger)
    {
        if (instance != null)
        {
            if (MethodToFunctionName.TryGetValue(method, out var functionName))
            {
                var finalArguments = new[] { instance }.Concat(arguments);

                if (method.ReturnType == typeof(bool))
                {
                    var nullCheck = (SqlExpression)_sqlExpressionFactory.IsNotNull(instance);
                    foreach (var argument in arguments)
                    {
                        nullCheck = _sqlExpressionFactory.AndAlso(
                            nullCheck,
                            _sqlExpressionFactory.IsNotNull(argument));
                    }

                    return(_sqlExpressionFactory.Case(
                               new[]
                    {
                        new CaseWhenClause(
                            nullCheck,
                            _sqlExpressionFactory.Function(
                                functionName,
                                finalArguments,
                                nullable: false,
                                finalArguments.Select(a => false),
                                method.ReturnType))
                    },
                               null));
                }

                return(_sqlExpressionFactory.Function(
                           functionName,
                           finalArguments,
                           nullable: true,
                           finalArguments.Select(a => true),
                           method.ReturnType));
            }

            if (Equals(method, GetGeometryN))
            {
                return(_sqlExpressionFactory.Function(
                           "GeometryN",
                           new[]
                {
                    instance,
                    _sqlExpressionFactory.Add(
                        arguments[0],
                        _sqlExpressionFactory.Constant(1))
                },
                           nullable: true,
                           argumentsPropagateNullability: new[] { true, true },
                           method.ReturnType));
            }

            if (Equals(method, IsWithinDistance))
            {
                return(_sqlExpressionFactory.LessThanOrEqual(
                           _sqlExpressionFactory.Function(
                               "Distance",
                               new[] { instance, arguments[0] },
                               nullable: true,
                               argumentsPropagateNullability: new[] { true, true },
                               typeof(double)),
                           arguments[1]));
            }
        }

        return(null);
    }
Пример #24
0
        public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments)
        {
            if (_indexOfMethodInfo.Equals(method))
            {
                var argument          = arguments[0];
                var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, argument);
                argument = _sqlExpressionFactory.ApplyTypeMapping(argument, stringTypeMapping);

                var charIndexExpression = _sqlExpressionFactory.Subtract(
                    _sqlExpressionFactory.Function(
                        "CHARINDEX",
                        new[] { argument, _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping) },
                        method.ReturnType),
                    _sqlExpressionFactory.Constant(1));

                return(_sqlExpressionFactory.Case(
                           new[]
                {
                    new CaseWhenClause(
                        _sqlExpressionFactory.Equal(
                            argument,
                            _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)),
                        _sqlExpressionFactory.Constant(0))
                },
                           charIndexExpression));
            }

            if (_replaceMethodInfo.Equals(method))
            {
                var firstArgument     = arguments[0];
                var secondArgument    = arguments[1];
                var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, firstArgument, secondArgument);

                instance       = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping);
                firstArgument  = _sqlExpressionFactory.ApplyTypeMapping(firstArgument, stringTypeMapping);
                secondArgument = _sqlExpressionFactory.ApplyTypeMapping(secondArgument, stringTypeMapping);

                return(_sqlExpressionFactory.Function(
                           "REPLACE",
                           new[] { instance, firstArgument, secondArgument },
                           method.ReturnType,
                           stringTypeMapping));
            }

            if (_toLowerMethodInfo.Equals(method) ||
                _toUpperMethodInfo.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           _toLowerMethodInfo.Equals(method) ? "LOWER" : "UPPER",
                           new[] { instance },
                           method.ReturnType,
                           instance.TypeMapping));
            }

            if (_substringMethodInfo.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           "SUBSTRING",
                           new[]
                {
                    instance,
                    _sqlExpressionFactory.Add(
                        arguments[0],
                        _sqlExpressionFactory.Constant(1)),
                    arguments[1]
                },
                           method.ReturnType,
                           instance.TypeMapping));
            }

            if (_isNullOrWhiteSpaceMethodInfo.Equals(method))
            {
                var argument = arguments[0];

                return(_sqlExpressionFactory.OrElse(
                           _sqlExpressionFactory.IsNull(argument),
                           _sqlExpressionFactory.Equal(
                               _sqlExpressionFactory.Function(
                                   "LTRIM",
                                   new[]
                {
                    _sqlExpressionFactory.Function(
                        "RTRIM",
                        new[] { argument },
                        argument.Type,
                        argument.TypeMapping)
                },
                                   argument.Type,
                                   argument.TypeMapping),
                               _sqlExpressionFactory.Constant(string.Empty, argument.TypeMapping))));
            }

            if (_trimStartMethodInfoWithoutArgs?.Equals(method) == true ||
                (_trimStartMethodInfoWithCharArrayArg.Equals(method)
                 // SqlServer LTRIM does not take arguments
                 && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0))
            {
                return(_sqlExpressionFactory.Function(
                           "LTRIM",
                           new[] { instance },
                           instance.Type,
                           instance.TypeMapping));
            }

            if (_trimEndMethodInfoWithoutArgs?.Equals(method) == true ||
                (_trimEndMethodInfoWithCharArrayArg.Equals(method)
                 // SqlServer RTRIM does not take arguments
                 && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0))
            {
                return(_sqlExpressionFactory.Function(
                           "RTRIM",
                           new[] { instance },
                           instance.Type,
                           instance.TypeMapping));
            }

            if (_trimMethodInfoWithoutArgs?.Equals(method) == true ||
                (_trimMethodInfoWithCharArrayArg.Equals(method)
                 // SqlServer LTRIM/RTRIM does not take arguments
                 && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0))
            {
                return(_sqlExpressionFactory.Function(
                           "LTRIM",
                           new[]
                {
                    _sqlExpressionFactory.Function(
                        "RTRIM",
                        new[] { instance },
                        instance.Type,
                        instance.TypeMapping)
                },
                           instance.Type,
                           instance.TypeMapping));
            }

            if (_containsMethodInfo.Equals(method))
            {
                var pattern           = arguments[0];
                var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, pattern);
                instance = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping);
                pattern  = _sqlExpressionFactory.ApplyTypeMapping(pattern, stringTypeMapping);

                if (pattern is SqlConstantExpression constantPattern)
                {
                    if ((string)constantPattern.Value == string.Empty)
                    {
                        return(_sqlExpressionFactory.Constant(true));
                    }

                    return(_sqlExpressionFactory.GreaterThan(
                               _sqlExpressionFactory.Function(
                                   "CHARINDEX",
                                   new[] { pattern, instance },
                                   typeof(int)),
                               _sqlExpressionFactory.Constant(0)));
                }

                return(_sqlExpressionFactory.OrElse(
                           _sqlExpressionFactory.Equal(
                               pattern,
                               _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)),
                           _sqlExpressionFactory.GreaterThan(
                               _sqlExpressionFactory.Function(
                                   "CHARINDEX",
                                   new[] { pattern, instance },
                                   typeof(int)),
                               _sqlExpressionFactory.Constant(0))));
            }

            if (_startsWithMethodInfo.Equals(method))
            {
                return(TranslateStartsEndsWith(instance, arguments[0], true));
            }

            if (_endsWithMethodInfo.Equals(method))
            {
                return(TranslateStartsEndsWith(instance, arguments[0], false));
            }

            return(null);
        }
        public virtual SqlExpression?Translate(
            SqlExpression?instance,
            MethodInfo method,
            IReadOnlyList <SqlExpression> arguments,
            IDiagnosticsLogger <DbLoggerCategory.Query> logger)
        {
            Check.NotNull(method, nameof(method));
            Check.NotNull(arguments, nameof(arguments));
            Check.NotNull(logger, nameof(logger));

            if (instance != null)
            {
                if (_indexOfMethodInfo.Equals(method))
                {
                    var argument          = arguments[0];
                    var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, argument) !;
                    argument = _sqlExpressionFactory.ApplyTypeMapping(argument, stringTypeMapping);

                    SqlExpression charIndexExpression;
                    var           storeType = stringTypeMapping.StoreType;
                    if (string.Equals(storeType, "nvarchar(max)", StringComparison.OrdinalIgnoreCase) ||
                        string.Equals(storeType, "varchar(max)", StringComparison.OrdinalIgnoreCase))
                    {
                        charIndexExpression = _sqlExpressionFactory.Function(
                            "CHARINDEX",
                            new[] { argument, _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping) },
                            nullable: true,
                            argumentsPropagateNullability: new[] { true, true },
                            typeof(long));

                        charIndexExpression = _sqlExpressionFactory.Convert(charIndexExpression, typeof(int));
                    }
                    else
                    {
                        charIndexExpression = _sqlExpressionFactory.Function(
                            "CHARINDEX",
                            new[] { argument, _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping) },
                            nullable: true,
                            argumentsPropagateNullability: new[] { true, true },
                            method.ReturnType);
                    }

                    charIndexExpression = _sqlExpressionFactory.Subtract(charIndexExpression, _sqlExpressionFactory.Constant(1));

                    return(_sqlExpressionFactory.Case(
                               new[]
                    {
                        new CaseWhenClause(
                            _sqlExpressionFactory.Equal(
                                argument,
                                _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)),
                            _sqlExpressionFactory.Constant(0))
                    },
                               charIndexExpression));
                }

                if (_replaceMethodInfo.Equals(method))
                {
                    var firstArgument     = arguments[0];
                    var secondArgument    = arguments[1];
                    var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, firstArgument, secondArgument);

                    instance       = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping);
                    firstArgument  = _sqlExpressionFactory.ApplyTypeMapping(firstArgument, stringTypeMapping);
                    secondArgument = _sqlExpressionFactory.ApplyTypeMapping(secondArgument, stringTypeMapping);

                    return(_sqlExpressionFactory.Function(
                               "REPLACE",
                               new[] { instance, firstArgument, secondArgument },
                               nullable: true,
                               argumentsPropagateNullability: new[] { true, true, true },
                               method.ReturnType,
                               stringTypeMapping));
                }

                if (_toLowerMethodInfo.Equals(method) ||
                    _toUpperMethodInfo.Equals(method))
                {
                    return(_sqlExpressionFactory.Function(
                               _toLowerMethodInfo.Equals(method) ? "LOWER" : "UPPER",
                               new[] { instance },
                               nullable: true,
                               argumentsPropagateNullability: new[] { true },
                               method.ReturnType,
                               instance.TypeMapping));
                }

                if (_substringMethodInfo.Equals(method))
                {
                    return(_sqlExpressionFactory.Function(
                               "SUBSTRING",
                               new[]
                    {
                        instance,
                        _sqlExpressionFactory.Add(
                            arguments[0],
                            _sqlExpressionFactory.Constant(1)),
                        arguments[1]
                    },
                               nullable: true,
                               argumentsPropagateNullability: new[] { true, true, true },
                               method.ReturnType,
                               instance.TypeMapping));
                }

                if (_trimStartMethodInfoWithoutArgs?.Equals(method) == true ||
                    (_trimStartMethodInfoWithCharArrayArg.Equals(method)
                     // SqlServer LTRIM does not take arguments
                     && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0))
                {
                    return(_sqlExpressionFactory.Function(
                               "LTRIM",
                               new[] { instance },
                               nullable: true,
                               argumentsPropagateNullability: new[] { true },
                               instance.Type,
                               instance.TypeMapping));
                }

                if (_trimEndMethodInfoWithoutArgs?.Equals(method) == true ||
                    (_trimEndMethodInfoWithCharArrayArg.Equals(method)
                     // SqlServer RTRIM does not take arguments
                     && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0))
                {
                    return(_sqlExpressionFactory.Function(
                               "RTRIM",
                               new[] { instance },
                               nullable: true,
                               argumentsPropagateNullability: new[] { true },
                               instance.Type,
                               instance.TypeMapping));
                }

                if (_trimMethodInfoWithoutArgs?.Equals(method) == true ||
                    (_trimMethodInfoWithCharArrayArg.Equals(method)
                     // SqlServer LTRIM/RTRIM does not take arguments
                     && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0))
                {
                    return(_sqlExpressionFactory.Function(
                               "LTRIM",
                               new[]
                    {
                        _sqlExpressionFactory.Function(
                            "RTRIM",
                            new[] { instance },
                            nullable: true,
                            argumentsPropagateNullability: new[] { true },
                            instance.Type,
                            instance.TypeMapping)
                    },
                               nullable: true,
                               argumentsPropagateNullability: new[] { true },
                               instance.Type,
                               instance.TypeMapping));
                }

                if (_containsMethodInfo.Equals(method))
                {
                    var pattern           = arguments[0];
                    var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, pattern);
                    instance = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping);
                    pattern  = _sqlExpressionFactory.ApplyTypeMapping(pattern, stringTypeMapping);

                    if (pattern is SqlConstantExpression constantPattern)
                    {
                        if (!(constantPattern.Value is string patternValue))
                        {
                            return(_sqlExpressionFactory.Like(
                                       instance,
                                       _sqlExpressionFactory.Constant(null, stringTypeMapping)));
                        }

                        if (patternValue.Length == 0)
                        {
                            return(_sqlExpressionFactory.Constant(true));
                        }

                        return(patternValue.Any(IsLikeWildChar)
                            ? _sqlExpressionFactory.Like(
                                   instance,
                                   _sqlExpressionFactory.Constant($"%{EscapeLikePattern(patternValue)}%"),
                                   _sqlExpressionFactory.Constant(LikeEscapeString))
                            : _sqlExpressionFactory.Like(instance, _sqlExpressionFactory.Constant($"%{patternValue}%")));
                    }

                    return(_sqlExpressionFactory.OrElse(
                               _sqlExpressionFactory.Like(
                                   pattern,
                                   _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)),
                               _sqlExpressionFactory.GreaterThan(
                                   _sqlExpressionFactory.Function(
                                       "CHARINDEX",
                                       new[] { pattern, instance },
                                       nullable: true,
                                       argumentsPropagateNullability: new[] { true, true },
                                       typeof(int)),
                                   _sqlExpressionFactory.Constant(0))));
                }

                if (_startsWithMethodInfo.Equals(method))
                {
                    return(TranslateStartsEndsWith(instance, arguments[0], true));
                }

                if (_endsWithMethodInfo.Equals(method))
                {
                    return(TranslateStartsEndsWith(instance, arguments[0], false));
                }
            }

            if (_isNullOrEmptyMethodInfo.Equals(method))
            {
                var argument = arguments[0];

                return(_sqlExpressionFactory.OrElse(
                           _sqlExpressionFactory.IsNull(argument),
                           _sqlExpressionFactory.Like(
                               argument,
                               _sqlExpressionFactory.Constant(string.Empty))));
            }

            if (_isNullOrWhiteSpaceMethodInfo.Equals(method))
            {
                var argument = arguments[0];

                return(_sqlExpressionFactory.OrElse(
                           _sqlExpressionFactory.IsNull(argument),
                           _sqlExpressionFactory.Equal(
                               argument,
                               _sqlExpressionFactory.Constant(string.Empty, argument.TypeMapping))));
            }

            if (_firstOrDefaultMethodInfoWithoutArgs.Equals(method))
            {
                var argument = arguments[0];
                return(_sqlExpressionFactory.Function(
                           "SUBSTRING",
                           new[] { argument, _sqlExpressionFactory.Constant(1), _sqlExpressionFactory.Constant(1) },
                           nullable: true,
                           argumentsPropagateNullability: new[] { true, true, true },
                           method.ReturnType));
            }

            if (_lastOrDefaultMethodInfoWithoutArgs.Equals(method))
            {
                var argument = arguments[0];
                return(_sqlExpressionFactory.Function(
                           "SUBSTRING",
                           new[]
                {
                    argument,
                    _sqlExpressionFactory.Function(
                        "LEN",
                        new[] { argument },
                        nullable: true,
                        argumentsPropagateNullability: new[] { true },
                        typeof(int)),
                    _sqlExpressionFactory.Constant(1)
                },
                           nullable: true,
                           argumentsPropagateNullability: new[] { true, true, true },
                           method.ReturnType));
            }

            return(null);
        }
Пример #26
0
        public virtual SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType)
        {
            Check.NotNull(member, nameof(member));
            Check.NotNull(returnType, nameof(returnType));

            if (typeof(Geometry).IsAssignableFrom(member.DeclaringType))
            {
                Check.DebugAssert(instance.TypeMapping != null, "Instance must have typeMapping assigned.");
                var storeType   = instance.TypeMapping.StoreType;
                var isGeography = string.Equals(storeType, "geography", StringComparison.OrdinalIgnoreCase);

                if (_memberToFunctionName.TryGetValue(member, out var functionName) ||
                    (!isGeography && _geometryMemberToFunctionName.TryGetValue(member, out functionName)))
                {
                    var resultTypeMapping = typeof(Geometry).IsAssignableFrom(returnType)
                        ? _typeMappingSource.FindMapping(returnType, storeType)
                        : _typeMappingSource.FindMapping(returnType);

                    return(_sqlExpressionFactory.Function(
                               instance,
                               functionName,
                               Array.Empty <SqlExpression>(),
                               nullResultAllowed: true,
                               instancePropagatesNullability: true,
                               argumentsPropagateNullability: Array.Empty <bool>(),
                               returnType,
                               resultTypeMapping));
                }

                if (Equals(member, _ogcGeometryType))
                {
                    var whenClauses = new List <CaseWhenClause>
                    {
                        new CaseWhenClause(
                            _sqlExpressionFactory.Constant("Point"), _sqlExpressionFactory.Constant(OgcGeometryType.Point)),
                        new CaseWhenClause(
                            _sqlExpressionFactory.Constant("LineString"), _sqlExpressionFactory.Constant(OgcGeometryType.LineString)),
                        new CaseWhenClause(
                            _sqlExpressionFactory.Constant("Polygon"), _sqlExpressionFactory.Constant(OgcGeometryType.Polygon)),
                        new CaseWhenClause(
                            _sqlExpressionFactory.Constant("MultiPoint"), _sqlExpressionFactory.Constant(OgcGeometryType.MultiPoint)),
                        new CaseWhenClause(
                            _sqlExpressionFactory.Constant("MultiLineString"),
                            _sqlExpressionFactory.Constant(OgcGeometryType.MultiLineString)),
                        new CaseWhenClause(
                            _sqlExpressionFactory.Constant("MultiPolygon"),
                            _sqlExpressionFactory.Constant(OgcGeometryType.MultiPolygon)),
                        new CaseWhenClause(
                            _sqlExpressionFactory.Constant("GeometryCollection"),
                            _sqlExpressionFactory.Constant(OgcGeometryType.GeometryCollection)),
                        new CaseWhenClause(
                            _sqlExpressionFactory.Constant("CircularString"),
                            _sqlExpressionFactory.Constant(OgcGeometryType.CircularString)),
                        new CaseWhenClause(
                            _sqlExpressionFactory.Constant("CompoundCurve"),
                            _sqlExpressionFactory.Constant(OgcGeometryType.CompoundCurve)),
                        new CaseWhenClause(
                            _sqlExpressionFactory.Constant("CurvePolygon"),
                            _sqlExpressionFactory.Constant(OgcGeometryType.CurvePolygon))
                    };

                    if (isGeography)
                    {
                        whenClauses.Add(
                            new CaseWhenClause(
                                _sqlExpressionFactory.Constant("FullGlobe"), _sqlExpressionFactory.Constant((OgcGeometryType)126)));
                    }

                    return(_sqlExpressionFactory.Case(
                               _sqlExpressionFactory.Function(
                                   instance,
                                   "STGeometryType",
                                   Array.Empty <SqlExpression>(),
                                   nullResultAllowed: true,
                                   instancePropagatesNullability: true,
                                   argumentsPropagateNullability: Array.Empty <bool>(),
                                   typeof(string)),
                               whenClauses.ToArray()));
                }

                if (Equals(member, _srid))
                {
                    return(_sqlExpressionFactory.Function(
                               instance,
                               "STSrid",
                               nullResultAllowed: true,
                               instancePropagatesNullability: true,
                               returnType));
                }
            }

            return(null);
        }
        public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments)
        {
            Check.NotNull(method, nameof(method));
            Check.NotNull(arguments, nameof(arguments));

            if (_indexOfMethodInfo.Equals(method))
            {
                var argument          = arguments[0];
                var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, argument);
                argument = _sqlExpressionFactory.ApplyTypeMapping(argument, stringTypeMapping);

                SqlExpression charIndexExpression;
                var           storeType = stringTypeMapping.StoreType;
                if (string.Equals(storeType, "nvarchar(max)", StringComparison.OrdinalIgnoreCase) ||
                    string.Equals(storeType, "varchar(max)", StringComparison.OrdinalIgnoreCase))
                {
                    charIndexExpression = _sqlExpressionFactory.Function(
                        "CHARINDEX",
                        new[] { argument, _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping) },
                        nullable: true,
                        argumentsPropagateNullability: new [] { true, true },
                        typeof(long));

                    charIndexExpression = _sqlExpressionFactory.Convert(charIndexExpression, typeof(int));
                }
                else
                {
                    charIndexExpression = _sqlExpressionFactory.Function(
                        "CHARINDEX",
                        new[] { argument, _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping) },
                        nullable: true,
                        argumentsPropagateNullability: new[] { true, true },
                        method.ReturnType);
                }

                charIndexExpression = _sqlExpressionFactory.Subtract(charIndexExpression, _sqlExpressionFactory.Constant(1));

                return(_sqlExpressionFactory.Case(
                           new[]
                {
                    new CaseWhenClause(
                        _sqlExpressionFactory.Equal(
                            argument,
                            _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)),
                        _sqlExpressionFactory.Constant(0))
                },
                           charIndexExpression));
            }

            if (_replaceMethodInfo.Equals(method))
            {
                var firstArgument     = arguments[0];
                var secondArgument    = arguments[1];
                var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, firstArgument, secondArgument);

                instance       = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping);
                firstArgument  = _sqlExpressionFactory.ApplyTypeMapping(firstArgument, stringTypeMapping);
                secondArgument = _sqlExpressionFactory.ApplyTypeMapping(secondArgument, stringTypeMapping);

                return(_sqlExpressionFactory.Function(
                           "REPLACE",
                           new[] { instance, firstArgument, secondArgument },
                           nullable: true,
                           argumentsPropagateNullability: new[] { true, true, true },
                           method.ReturnType,
                           stringTypeMapping));
            }

            if (_toLowerMethodInfo.Equals(method) ||
                _toUpperMethodInfo.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           _toLowerMethodInfo.Equals(method) ? "LOWER" : "UPPER",
                           new[] { instance },
                           nullable: true,
                           argumentsPropagateNullability: new[] { true },
                           method.ReturnType,
                           instance.TypeMapping));
            }

            if (_substringMethodInfo.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           "SUBSTRING",
                           new[]
                {
                    instance,
                    _sqlExpressionFactory.Add(
                        arguments[0],
                        _sqlExpressionFactory.Constant(1)),
                    arguments[1]
                },
                           nullable: true,
                           argumentsPropagateNullability: new[] { true, true, true },
                           method.ReturnType,
                           instance.TypeMapping));
            }

            if (_isNullOrWhiteSpaceMethodInfo.Equals(method))
            {
                var argument = arguments[0];

                return(_sqlExpressionFactory.OrElse(
                           _sqlExpressionFactory.IsNull(argument),
                           _sqlExpressionFactory.Equal(
                               _sqlExpressionFactory.Function(
                                   "LTRIM",
                                   new[]
                {
                    _sqlExpressionFactory.Function(
                        "RTRIM",
                        new[] { argument },
                        nullable: true,
                        argumentsPropagateNullability: new[] { true },
                        argument.Type,
                        argument.TypeMapping)
                },
                                   nullable: true,
                                   argumentsPropagateNullability: new[] { true },
                                   argument.Type,
                                   argument.TypeMapping),
                               _sqlExpressionFactory.Constant(string.Empty, argument.TypeMapping))));
            }

            if (_trimStartMethodInfoWithoutArgs?.Equals(method) == true ||
                (_trimStartMethodInfoWithCharArrayArg.Equals(method)
                 // SqlServer LTRIM does not take arguments
                 && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0))
            {
                return(_sqlExpressionFactory.Function(
                           "LTRIM",
                           new[] { instance },
                           nullable: true,
                           argumentsPropagateNullability: new[] { true },
                           instance.Type,
                           instance.TypeMapping));
            }

            if (_trimEndMethodInfoWithoutArgs?.Equals(method) == true ||
                (_trimEndMethodInfoWithCharArrayArg.Equals(method)
                 // SqlServer RTRIM does not take arguments
                 && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0))
            {
                return(_sqlExpressionFactory.Function(
                           "RTRIM",
                           new[] { instance },
                           nullable: true,
                           argumentsPropagateNullability: new[] { true },
                           instance.Type,
                           instance.TypeMapping));
            }

            if (_trimMethodInfoWithoutArgs?.Equals(method) == true ||
                (_trimMethodInfoWithCharArrayArg.Equals(method)
                 // SqlServer LTRIM/RTRIM does not take arguments
                 && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0))
            {
                return(_sqlExpressionFactory.Function(
                           "LTRIM",
                           new[]
                {
                    _sqlExpressionFactory.Function(
                        "RTRIM",
                        new[] { instance },
                        nullable: true,
                        argumentsPropagateNullability: new[] { true },
                        instance.Type,
                        instance.TypeMapping)
                },
                           nullable: true,
                           argumentsPropagateNullability: new[] { true },
                           instance.Type,
                           instance.TypeMapping));
            }

            if (_containsMethodInfo.Equals(method))
            {
                var pattern           = arguments[0];
                var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, pattern);
                instance = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping);
                pattern  = _sqlExpressionFactory.ApplyTypeMapping(pattern, stringTypeMapping);

                if (pattern is SqlConstantExpression constantPattern)
                {
                    // Intentionally string.Empty since we don't want to match nulls here.
#pragma warning disable CA1820 // Test for empty strings using string length
                    if ((string)constantPattern.Value == string.Empty)
#pragma warning restore CA1820 // Test for empty strings using string length
                    {
                        return(_sqlExpressionFactory.Constant(true));
                    }

                    return(_sqlExpressionFactory.GreaterThan(
                               _sqlExpressionFactory.Function(
                                   "CHARINDEX",
                                   new[] { pattern, instance },
                                   nullable: true,
                                   argumentsPropagateNullability: new[] { true, true },
                                   typeof(int)),
                               _sqlExpressionFactory.Constant(0)));
                }

                return(_sqlExpressionFactory.OrElse(
                           _sqlExpressionFactory.Equal(
                               pattern,
                               _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)),
                           _sqlExpressionFactory.GreaterThan(
                               _sqlExpressionFactory.Function(
                                   "CHARINDEX",
                                   new[] { pattern, instance },
                                   nullable: true,
                                   argumentsPropagateNullability: new[] { true, true },
                                   typeof(int)),
                               _sqlExpressionFactory.Constant(0))));
            }

            if (_startsWithMethodInfo.Equals(method))
            {
                return(TranslateStartsEndsWith(instance, arguments[0], true));
            }

            if (_endsWithMethodInfo.Equals(method))
            {
                return(TranslateStartsEndsWith(instance, arguments[0], false));
            }

            return(null);
        }
    public virtual SqlExpression?Translate(
        SqlExpression?instance,
        MemberInfo member,
        Type returnType,
        IDiagnosticsLogger <DbLoggerCategory.Query> logger)
    {
        var declaringType = member.DeclaringType;

        if (instance is null || !typeof(Geometry).IsAssignableFrom(declaringType))
        {
            return(null);
        }

        var typeMapping = instance.TypeMapping;

        Debug.Assert(typeMapping is not null, "Instance must have typeMapping assigned.");
        var storeType = instance.TypeMapping !.StoreType;

        if (typeof(Point).IsAssignableFrom(declaringType))
        {
            var function = member.Name switch
            {
                nameof(Point.X) => "ST_X",
                nameof(Point.Y) => "ST_Y",
                nameof(Point.Z) => "ST_Z",
                nameof(Point.M) => "ST_M",
                _ => null
            };

            if (function is not null)
            {
                return(Function(function, new[] { instance }, typeof(double)));
            }
        }

        if (typeof(LineString).IsAssignableFrom(declaringType))
        {
            if (member.Name == "Count")
            {
                return(Function("ST_NumPoints", new[] { instance }, typeof(int)));
            }
        }

        return(member.Name switch
        {
            nameof(Geometry.Area) => Function("ST_Area", new[] { instance }, typeof(double)),
            nameof(Geometry.Boundary) => Function("ST_Boundary", new[] { instance }, typeof(Geometry), ResultGeometryMapping()),
            nameof(Geometry.Centroid) => Function("ST_Centroid", new[] { instance }, typeof(Point), ResultGeometryMapping()),
            nameof(GeometryCollection.Count) => Function("ST_NumGeometries", new[] { instance }, typeof(int)),
            nameof(Geometry.Dimension) => Function("ST_Dimension", new[] { instance }, typeof(Dimension)),
            nameof(LineString.EndPoint) => Function("ST_EndPoint", new[] { instance }, typeof(Point), ResultGeometryMapping()),
            nameof(Geometry.Envelope) => Function("ST_Envelope", new[] { instance }, typeof(Geometry), ResultGeometryMapping()),
            nameof(Polygon.ExteriorRing) => Function("ST_ExteriorRing", new[] { instance }, typeof(LineString), ResultGeometryMapping()),
            nameof(Geometry.GeometryType) => Function("GeometryType", new[] { instance }, typeof(string)),
            nameof(LineString.IsClosed) => Function("ST_IsClosed", new[] { instance }, typeof(bool)),
            nameof(Geometry.IsEmpty) => Function("ST_IsEmpty", new[] { instance }, typeof(bool)),
            nameof(LineString.IsRing) => Function("ST_IsRing", new[] { instance }, typeof(bool)),
            nameof(Geometry.IsSimple) => Function("ST_IsSimple", new[] { instance }, typeof(bool)),
            nameof(Geometry.IsValid) => Function("ST_IsValid", new[] { instance }, typeof(bool)),
            nameof(Geometry.Length) => Function("ST_Length", new[] { instance }, typeof(double)),
            nameof(Geometry.NumGeometries) => Function("ST_NumGeometries", new[] { instance }, typeof(int)),
            nameof(Polygon.NumInteriorRings) => Function("ST_NumInteriorRings", new[] { instance }, typeof(int)),
            nameof(Geometry.NumPoints) => Function("ST_NumPoints", new[] { instance }, typeof(int)),
            nameof(Geometry.PointOnSurface) => Function("ST_PointOnSurface", new[] { instance }, typeof(Geometry), ResultGeometryMapping()),
            nameof(Geometry.InteriorPoint) => Function("ST_PointOnSurface", new[] { instance }, typeof(Geometry), ResultGeometryMapping()),
            nameof(Geometry.SRID) => Function("ST_SRID", new[] { instance }, typeof(int)),
            nameof(LineString.StartPoint) => Function("ST_StartPoint", new[] { instance }, typeof(Point), ResultGeometryMapping()),

            nameof(Geometry.OgcGeometryType) => _sqlExpressionFactory.Case(
                Function("ST_GeometryType", new[] { instance }, typeof(string)),
                _ogcGeometryTypeWhenThenList,
                elseResult: null),

            _ => null
        });
        public SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType)
        {
            member = member.OnInterface(typeof(IGeometry));
            if (_memberToFunctionName.TryGetValue(member, out var functionName))
            {
                SqlExpression translation = _sqlExpressionFactory.Function(functionName, new[] { instance }, returnType);

                if (returnType == typeof(bool))
                {
                    translation = _sqlExpressionFactory.Case(
                        new[]
                    {
                        new CaseWhenClause(
                            _sqlExpressionFactory.IsNotNull(instance),
                            translation)
                    },
                        null);
                }

                return(translation);
            }

            if (Equals(member, _geometryType))
            {
                return(_sqlExpressionFactory.Case(
                           _sqlExpressionFactory.Function(
                               "rtrim",
                               new SqlExpression[]
                {
                    _sqlExpressionFactory.Function(
                        "GeometryType",
                        new []
                    {
                        instance,
                    },
                        returnType),
                    _sqlExpressionFactory.Constant(" ZM")
                },
                               returnType),
                           new CaseWhenClause(_sqlExpressionFactory.Constant("POINT"), _sqlExpressionFactory.Constant("Point")),
                           new CaseWhenClause(_sqlExpressionFactory.Constant("LINESTRING"), _sqlExpressionFactory.Constant("LineString")),
                           new CaseWhenClause(_sqlExpressionFactory.Constant("POLYGON"), _sqlExpressionFactory.Constant("Polygon")),
                           new CaseWhenClause(_sqlExpressionFactory.Constant("MULTIPOINT"), _sqlExpressionFactory.Constant("MultiPoint")),
                           new CaseWhenClause(_sqlExpressionFactory.Constant("MULTILINESTRING"), _sqlExpressionFactory.Constant("MultiLineString")),
                           new CaseWhenClause(_sqlExpressionFactory.Constant("MULTIPOLYGON"), _sqlExpressionFactory.Constant("MultiPolygon")),
                           new CaseWhenClause(_sqlExpressionFactory.Constant("GEOMETRYCOLLECTION"), _sqlExpressionFactory.Constant("GeometryCollection"))));
            }

            if (Equals(member, _ogcGeometryType))
            {
                return(_sqlExpressionFactory.Case(
                           _sqlExpressionFactory.Function(
                               "rtrim",
                               new SqlExpression[]
                {
                    _sqlExpressionFactory.Function(
                        "GeometryType",
                        new []
                    {
                        instance,
                    },
                        typeof(string)),
                    _sqlExpressionFactory.Constant(" ZM")
                },
                               typeof(string)),
                           new CaseWhenClause(_sqlExpressionFactory.Constant("POINT"), _sqlExpressionFactory.Constant(OgcGeometryType.Point)),
                           new CaseWhenClause(_sqlExpressionFactory.Constant("LINESTRING"), _sqlExpressionFactory.Constant(OgcGeometryType.LineString)),
                           new CaseWhenClause(_sqlExpressionFactory.Constant("POLYGON"), _sqlExpressionFactory.Constant(OgcGeometryType.Polygon)),
                           new CaseWhenClause(_sqlExpressionFactory.Constant("MULTIPOINT"), _sqlExpressionFactory.Constant(OgcGeometryType.MultiPoint)),
                           new CaseWhenClause(_sqlExpressionFactory.Constant("MULTILINESTRING"), _sqlExpressionFactory.Constant(OgcGeometryType.MultiLineString)),
                           new CaseWhenClause(_sqlExpressionFactory.Constant("MULTIPOLYGON"), _sqlExpressionFactory.Constant(OgcGeometryType.MultiPolygon)),
                           new CaseWhenClause(_sqlExpressionFactory.Constant("GEOMETRYCOLLECTION"), _sqlExpressionFactory.Constant(OgcGeometryType.GeometryCollection))));
            }

            return(null);
        }
    /// <summary>
    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
    ///     any release. You should only use it directly in your code with extreme caution and knowing that
    ///     doing so can result in application failures when updating to a new Entity Framework Core release.
    /// </summary>
    public virtual SqlExpression?Translate(
        SqlExpression?instance,
        MemberInfo member,
        Type returnType,
        IDiagnosticsLogger <DbLoggerCategory.Query> logger)
    {
        if (instance != null)
        {
            if (MemberToFunctionName.TryGetValue(member, out var functionName))
            {
                return(returnType == typeof(bool)
                    ? _sqlExpressionFactory.Case(
                           new[]
                {
                    new CaseWhenClause(
                        _sqlExpressionFactory.IsNotNull(instance),
                        _sqlExpressionFactory.Function(
                            functionName,
                            new[] { instance },
                            nullable: false,
                            argumentsPropagateNullability: new[] { false },
                            returnType))
                },
                           null)
                    : _sqlExpressionFactory.Function(
                           functionName,
                           new[] { instance },
                           nullable: true,
                           argumentsPropagateNullability: new[] { true },
                           returnType));
            }

            if (Equals(member, GeometryType))
            {
                return(_sqlExpressionFactory.Case(
                           _sqlExpressionFactory.Function(
                               "rtrim",
                               new SqlExpression[]
                {
                    _sqlExpressionFactory.Function(
                        "GeometryType",
                        new[] { instance },
                        nullable: true,
                        argumentsPropagateNullability: new[] { true },
                        returnType),
                    _sqlExpressionFactory.Constant(" ZM")
                },
                               nullable: true,
                               argumentsPropagateNullability: new[] { true },
                               returnType),
                           new[]
                {
                    new CaseWhenClause(_sqlExpressionFactory.Constant("POINT"), _sqlExpressionFactory.Constant("Point")),
                    new CaseWhenClause(_sqlExpressionFactory.Constant("LINESTRING"), _sqlExpressionFactory.Constant("LineString")),
                    new CaseWhenClause(_sqlExpressionFactory.Constant("POLYGON"), _sqlExpressionFactory.Constant("Polygon")),
                    new CaseWhenClause(_sqlExpressionFactory.Constant("MULTIPOINT"), _sqlExpressionFactory.Constant("MultiPoint")),
                    new CaseWhenClause(
                        _sqlExpressionFactory.Constant("MULTILINESTRING"), _sqlExpressionFactory.Constant("MultiLineString")),
                    new CaseWhenClause(
                        _sqlExpressionFactory.Constant("MULTIPOLYGON"), _sqlExpressionFactory.Constant("MultiPolygon")),
                    new CaseWhenClause(
                        _sqlExpressionFactory.Constant("GEOMETRYCOLLECTION"), _sqlExpressionFactory.Constant("GeometryCollection"))
                },
                           null));
            }

            if (Equals(member, OgcGeometryType))
            {
                return(_sqlExpressionFactory.Case(
                           _sqlExpressionFactory.Function(
                               "rtrim",
                               new SqlExpression[]
                {
                    _sqlExpressionFactory.Function(
                        "GeometryType",
                        new[] { instance },
                        nullable: true,
                        argumentsPropagateNullability: new[] { true },
                        typeof(string)),
                    _sqlExpressionFactory.Constant(" ZM")
                },
                               nullable: true,
                               argumentsPropagateNullability: new[] { true },
                               typeof(string)),
                           new[]
                {
                    new CaseWhenClause(
                        _sqlExpressionFactory.Constant("POINT"), _sqlExpressionFactory.Constant(NetTopologySuite.Geometries.OgcGeometryType.Point)),
                    new CaseWhenClause(
                        _sqlExpressionFactory.Constant("LINESTRING"), _sqlExpressionFactory.Constant(NetTopologySuite.Geometries.OgcGeometryType.LineString)),
                    new CaseWhenClause(
                        _sqlExpressionFactory.Constant("POLYGON"), _sqlExpressionFactory.Constant(NetTopologySuite.Geometries.OgcGeometryType.Polygon)),
                    new CaseWhenClause(
                        _sqlExpressionFactory.Constant("MULTIPOINT"), _sqlExpressionFactory.Constant(NetTopologySuite.Geometries.OgcGeometryType.MultiPoint)),
                    new CaseWhenClause(
                        _sqlExpressionFactory.Constant("MULTILINESTRING"),
                        _sqlExpressionFactory.Constant(NetTopologySuite.Geometries.OgcGeometryType.MultiLineString)),
                    new CaseWhenClause(
                        _sqlExpressionFactory.Constant("MULTIPOLYGON"),
                        _sqlExpressionFactory.Constant(NetTopologySuite.Geometries.OgcGeometryType.MultiPolygon)),
                    new CaseWhenClause(
                        _sqlExpressionFactory.Constant("GEOMETRYCOLLECTION"),
                        _sqlExpressionFactory.Constant(NetTopologySuite.Geometries.OgcGeometryType.GeometryCollection))
                },
                           null));
            }
        }

        return(null);
    }