Example #1
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));

            var declaringType = member.DeclaringType;

            if (declaringType == typeof(DateTime) ||
                declaringType == typeof(DateTimeOffset))
            {
                var memberName = member.Name;

                if (_datePartMapping.TryGetValue(memberName, out var datePart))
                {
                    return(_sqlExpressionFactory.Function(
                               "DATEPART",
                               new[] { _sqlExpressionFactory.Fragment(datePart), instance },
                               nullable: true,
                               argumentsPropagateNullability: new[] { false, true },
                               returnType));
                }

                switch (memberName)
                {
                case nameof(DateTime.Date):
                    return(_sqlExpressionFactory.Function(
                               "CONVERT",
                               new[] { _sqlExpressionFactory.Fragment("date"), instance },
                               nullable: true,
                               argumentsPropagateNullability: new[] { false, true },
                               returnType,
                               declaringType == typeof(DateTime)
                                ? instance.TypeMapping
                                : _typeMappingSource.FindMapping(typeof(DateTime))));

                case nameof(DateTime.TimeOfDay):
                    return(_sqlExpressionFactory.Convert(instance, returnType));

                case nameof(DateTime.Now):
                    return(_sqlExpressionFactory.Function(
                               declaringType == typeof(DateTime) ? "GETDATE" : "SYSDATETIMEOFFSET",
                               Array.Empty <SqlExpression>(),
                               nullable: false,
                               argumentsPropagateNullability: Array.Empty <bool>(),
                               returnType));

                case nameof(DateTime.UtcNow):
                    var serverTranslation = _sqlExpressionFactory.Function(
                        declaringType == typeof(DateTime) ? "GETUTCDATE" : "SYSUTCDATETIME",
                        Array.Empty <SqlExpression>(),
                        nullable: false,
                        argumentsPropagateNullability: Array.Empty <bool>(),
                        returnType);

                    return(declaringType == typeof(DateTime)
                            ? (SqlExpression)serverTranslation
                            : _sqlExpressionFactory.Convert(serverTranslation, returnType));

                case nameof(DateTime.Today):
                    return(_sqlExpressionFactory.Function(
                               "CONVERT",
                               new SqlExpression[]
                    {
                        _sqlExpressionFactory.Fragment("date"),
                        _sqlExpressionFactory.Function(
                            "GETDATE",
                            Array.Empty <SqlExpression>(),
                            nullable: false,
                            argumentsPropagateNullability: Array.Empty <bool>(),
                            typeof(DateTime))
                    },
                               nullable: true,
                               argumentsPropagateNullability: new[] { false, true },
                               returnType));
                }
            }

            return(null);
        }
        public virtual SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType)
        {
            if (member.DeclaringType == typeof(DateTime))
            {
                var memberName = member.Name;

                if (_datePartMapping.TryGetValue(memberName, out var datePart))
                {
                    return(_sqlExpressionFactory.Convert(
                               SqliteExpression.Strftime(
                                   _sqlExpressionFactory,
                                   typeof(string),
                                   datePart,
                                   instance),
                               returnType));
                }

                if (string.Equals(memberName, nameof(DateTime.Ticks)))
                {
                    return(_sqlExpressionFactory.Convert(
                               _sqlExpressionFactory.Multiply(
                                   _sqlExpressionFactory.Subtract(
                                       _sqlExpressionFactory.Function(
                                           "julianday",
                                           new[] { instance },
                                           typeof(double)),
                                       _sqlExpressionFactory.Constant(1721425.5)), // NB: Result of julianday('0001-01-01 00:00:00')
                                   _sqlExpressionFactory.Constant(TimeSpan.TicksPerDay)),
                               typeof(long)));
                }

                if (string.Equals(memberName, nameof(DateTime.Millisecond)))
                {
                    return(_sqlExpressionFactory.Modulo(
                               _sqlExpressionFactory.Multiply(
                                   _sqlExpressionFactory.Convert(
                                       SqliteExpression.Strftime(
                                           _sqlExpressionFactory,
                                           typeof(string),
                                           "%f",
                                           instance),
                                       typeof(double)),
                                   _sqlExpressionFactory.Constant(1000)),
                               _sqlExpressionFactory.Constant(1000)));
                }

                var           format = "%Y-%m-%d %H:%M:%f";
                SqlExpression timestring;
                var           modifiers = new List <SqlExpression>();

                switch (memberName)
                {
                case nameof(DateTime.Now):
                    timestring = _sqlExpressionFactory.Constant("now");
                    modifiers.Add(_sqlExpressionFactory.Constant("localtime"));
                    break;

                case nameof(DateTime.UtcNow):
                    timestring = _sqlExpressionFactory.Constant("now");
                    break;

                case nameof(DateTime.Date):
                    timestring = instance;
                    modifiers.Add(_sqlExpressionFactory.Constant("start of day"));
                    break;

                case nameof(DateTime.Today):
                    timestring = _sqlExpressionFactory.Constant("now");
                    modifiers.Add(_sqlExpressionFactory.Constant("localtime"));
                    modifiers.Add(_sqlExpressionFactory.Constant("start of day"));
                    break;

                case nameof(DateTime.TimeOfDay):
                    format     = "%H:%M:%f";
                    timestring = instance;
                    break;

                default:
                    return(null);
                }

                Debug.Assert(timestring != null);

                return(_sqlExpressionFactory.Function(
                           "rtrim",
                           new SqlExpression[]
                {
                    _sqlExpressionFactory.Function(
                        "rtrim",
                        new SqlExpression[]
                    {
                        SqliteExpression.Strftime(
                            _sqlExpressionFactory,
                            returnType,
                            format,
                            timestring,
                            modifiers),
                        _sqlExpressionFactory.Constant("0")
                    },
                        returnType),
                    _sqlExpressionFactory.Constant(".")
                },
                           returnType));
            }

            return(null);
        }
        public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments, IDiagnosticsLogger <DbLoggerCategory.Query> logger)
        {
            if (Exp.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           name: "exp",
                           arguments: arguments,
                           nullable: false,
                           argumentsPropagateNullability: new[] { true },
                           returnType: method.ReturnType));
            }

            if (Log.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           name: "log",
                           arguments: arguments,
                           nullable: false,
                           argumentsPropagateNullability: new[] { true },
                           returnType: method.ReturnType));
            }

            if (Log10.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           name: "log10",
                           arguments: arguments,
                           nullable: false,
                           argumentsPropagateNullability: new[] { true },
                           returnType: method.ReturnType));
            }

            if (Sqrt.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           name: "sqrt",
                           arguments: arguments,
                           nullable: false,
                           argumentsPropagateNullability: new[] { true },
                           returnType: method.ReturnType));
            }

            if (Cbrt.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           name: "cbrt",
                           arguments: arguments,
                           nullable: false,
                           argumentsPropagateNullability: new[] { true },
                           returnType: method.ReturnType));
            }

            if (Sin.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           name: "sin",
                           arguments: arguments,
                           nullable: false,
                           argumentsPropagateNullability: new[] { true },
                           returnType: method.ReturnType));
            }

            if (Cos.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           name: "cos",
                           arguments: arguments,
                           nullable: false,
                           argumentsPropagateNullability: new[] { true },
                           returnType: method.ReturnType));
            }

            if (Tan.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           name: "tan",
                           arguments: arguments,
                           nullable: false,
                           argumentsPropagateNullability: new[] { true },
                           returnType: method.ReturnType));
            }

            if (Asin.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           name: "asin",
                           arguments: arguments,
                           nullable: false,
                           argumentsPropagateNullability: new[] { true },
                           returnType: method.ReturnType));
            }

            if (Acos.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           name: "Acos",
                           arguments: arguments,
                           nullable: false,
                           argumentsPropagateNullability: new[] { true },
                           returnType: method.ReturnType));
            }

            if (Atan.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           name: "atan",
                           arguments: arguments,
                           nullable: false,
                           argumentsPropagateNullability: new[] { true },
                           returnType: method.ReturnType));
            }

            if (Pow.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           name: "pow",
                           arguments: arguments,
                           nullable: false,
                           argumentsPropagateNullability: new[] { true },
                           returnType: method.ReturnType));
            }

            /*
             * if (Cosh.Equals(method))
             * {
             *  return _sqlExpressionFactory.Function(
             *      name: "cosh",
             *      arguments: arguments,
             *      nullable: false,
             *      argumentsPropagateNullability: new[] { true },
             *      returnType: typeof(double));
             * }
             *
             * if (Acosh.Equals(method))
             * {
             *  return _sqlExpressionFactory.Function(
             *      name: "acosh",
             *      arguments: arguments,
             *      nullable: false,
             *      argumentsPropagateNullability: new[] { true },
             *      returnType: typeof(double));
             * }
             */

            if (CeilingDouble.Equals(method) || CeilingDecimal.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           name: "ceiling",
                           arguments: arguments,
                           nullable: false,
                           argumentsPropagateNullability: new[] { true },
                           returnType: method.ReturnType));
            }

            if (RoundDouble.Equals(method) || RoundDecimal.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           name: "round",
                           arguments: arguments,
                           nullable: false,
                           argumentsPropagateNullability: new[] { true },
                           returnType: method.ReturnType));
            }

            return(null);
        }
Example #4
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 (typeof(Polygon).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 (isGeography)
                {
                    if (Equals(_exteriorRing, member))
                    {
                        return(_sqlExpressionFactory.Function(
                                   instance,
                                   "RingN",
                                   new[] { _sqlExpressionFactory.Constant(1) },
                                   nullable: true,
                                   instancePropagatesNullability: true,
                                   argumentsPropagateNullability: new[] { false },
                                   returnType,
                                   _typeMappingSource.FindMapping(returnType, storeType)));
                    }

                    if (Equals(_numInteriorRings, member))
                    {
                        return(_sqlExpressionFactory.Subtract(
                                   _sqlExpressionFactory.Function(
                                       instance,
                                       "NumRings",
                                       Array.Empty <SqlExpression>(),
                                       nullable: true,
                                       instancePropagatesNullability: true,
                                       argumentsPropagateNullability: Array.Empty <bool>(),
                                       returnType),
                                   _sqlExpressionFactory.Constant(1)));
                    }
                }

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

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

            return(null);
        }
Example #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,
        MethodInfo method,
        IReadOnlyList <SqlExpression> arguments,
        IDiagnosticsLogger <DbLoggerCategory.Query> logger)
    {
        if (instance != null)
        {
            if (IndexOfMethodInfo.Equals(method))
            {
                return(TranslateIndexOf(instance, method, arguments[0], null));
            }

            if (IndexOfMethodInfoWithStartingPosition.Equals(method))
            {
                return(TranslateIndexOf(instance, method, arguments[0], arguments[1]));
            }

            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 (SubstringMethodInfoWithOneArg.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           "SUBSTRING",
                           new[]
                {
                    instance,
                    _sqlExpressionFactory.Add(
                        arguments[0],
                        _sqlExpressionFactory.Constant(1)),
                    _sqlExpressionFactory.Function(
                        "LEN",
                        new[] { instance },
                        nullable: true,
                        argumentsPropagateNullability: new[] { true },
                        typeof(int))
                },
                           nullable: true,
                           argumentsPropagateNullability: new[] { true, true, true },
                           method.ReturnType,
                           instance.TypeMapping));
            }

            if (SubstringMethodInfoWithTwoArgs.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);
    }
Example #6
0
        public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments)
        {
            Check.NotNull(method, nameof(method));
            Check.NotNull(arguments, nameof(arguments));

            SqlExpression modifier = null;

            if (_addMilliseconds.Equals(method))
            {
                modifier = _sqlExpressionFactory.Add(
                    _sqlExpressionFactory.Convert(
                        _sqlExpressionFactory.Divide(
                            arguments[0],
                            _sqlExpressionFactory.Constant(1000.0)),
                        typeof(string)),
                    _sqlExpressionFactory.Constant(" seconds"));
            }
            else if (_addTicks.Equals(method))
            {
                modifier = _sqlExpressionFactory.Add(
                    _sqlExpressionFactory.Convert(
                        _sqlExpressionFactory.Divide(
                            arguments[0],
                            _sqlExpressionFactory.Constant((double)TimeSpan.TicksPerDay)),
                        typeof(string)),
                    _sqlExpressionFactory.Constant(" seconds"));
            }
            else if (_methodInfoToUnitSuffix.TryGetValue(method, out var unitSuffix))
            {
                modifier = _sqlExpressionFactory.Add(
                    _sqlExpressionFactory.Convert(arguments[0], typeof(string)),
                    _sqlExpressionFactory.Constant(unitSuffix));
            }

            if (modifier != null)
            {
                return(_sqlExpressionFactory.Function(
                           "rtrim",
                           new SqlExpression[]
                {
                    _sqlExpressionFactory.Function(
                        "rtrim",
                        new SqlExpression[]
                    {
                        SqliteExpression.Strftime(
                            _sqlExpressionFactory,
                            method.ReturnType,
                            "%Y-%m-%d %H:%M:%f",
                            instance,
                            new[] { modifier }),
                        _sqlExpressionFactory.Constant("0")
                    },
                        nullable: true,
                        argumentsPropagateNullability: new[] { true, false },
                        method.ReturnType),
                    _sqlExpressionFactory.Constant(".")
                },
                           nullable: true,
                           argumentsPropagateNullability: new[] { true, false },
                           method.ReturnType));
            }

            return(null);
        }
Example #7
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 (_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)
                {
                    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 (_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));
            }

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

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

            return(null);
        }
Example #8
0
 private SqlExpression TranslateSystemFunction(string function, SqlExpression instance, SqlExpression pattern, Type returnType)
 => _sqlExpressionFactory.Function(function, new[] { instance, pattern }, returnType);
        public SqlExpression Translate(SqlExpression instance, MethodInfo method, IList <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);
        }
Example #10
0
        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);

                return(_sqlExpressionFactory.Subtract(
                           _sqlExpressionFactory.Function(
                               "instr",
                               new[]
                {
                    _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping),
                    _sqlExpressionFactory.ApplyTypeMapping(argument, stringTypeMapping)
                },
                               method.ReturnType),
                           _sqlExpressionFactory.Constant(1)));
            }

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

                return(_sqlExpressionFactory.Function(
                           "replace",
                           new[]
                {
                    _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping),
                    _sqlExpressionFactory.ApplyTypeMapping(firstArgument, stringTypeMapping),
                    _sqlExpressionFactory.ApplyTypeMapping(secondArgument, stringTypeMapping)
                },
                           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(
                           "substr",
                           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(
                                   "trim", new[] { argument }, argument.Type, argument.TypeMapping),
                               _sqlExpressionFactory.Constant(string.Empty))));
            }

            if (_trimStartMethodInfoWithoutArgs?.Equals(method) == true ||
                _trimStartMethodInfoWithCharArg?.Equals(method) == true ||
                _trimStartMethodInfoWithCharArrayArg.Equals(method))
            {
                return(ProcessTrimMethod(instance, arguments, "ltrim"));
            }

            if (_trimEndMethodInfoWithoutArgs?.Equals(method) == true ||
                _trimEndMethodInfoWithCharArg?.Equals(method) == true ||
                _trimEndMethodInfoWithCharArrayArg.Equals(method))
            {
                return(ProcessTrimMethod(instance, arguments, "rtrim"));
            }

            if (_trimMethodInfoWithoutArgs?.Equals(method) == true ||
                _trimMethodInfoWithCharArg?.Equals(method) == true ||
                _trimMethodInfoWithCharArrayArg.Equals(method))
            {
                return(ProcessTrimMethod(instance, arguments, "trim"));
            }

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

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

                return(_sqlExpressionFactory.OrElse(
                           _sqlExpressionFactory.Equal(
                               pattern,
                               _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)),
                           _sqlExpressionFactory.GreaterThan(
                               _sqlExpressionFactory.Function(
                                   "instr",
                                   new[] { instance, pattern },
                                   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 SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType)
        {
            var declaringType = member.DeclaringType;

            if (declaringType == typeof(DateTime) ||
                declaringType == typeof(DateTimeOffset))
            {
                var memberName = member.Name;

                if (_datePartMapping.TryGetValue(memberName, out var datePart))
                {
                    return(_sqlExpressionFactory.Function(
                               "DATEPART",
                               new[]
                    {
                        _sqlExpressionFactory.Fragment(datePart),
                        instance
                    },
                               returnType));
                }

                switch (memberName)
                {
                case nameof(DateTime.Date):
                    return(_sqlExpressionFactory.Function(
                               "CONVERT",
                               new[] {
                        _sqlExpressionFactory.Fragment("date"),
                        instance
                    },
                               returnType,
                               instance.TypeMapping));

                case nameof(DateTime.TimeOfDay):
                    return(_sqlExpressionFactory.Convert(instance, returnType));

                case nameof(DateTime.Now):
                    return(_sqlExpressionFactory.Function(
                               declaringType == typeof(DateTime) ? "GETDATE" : "SYSDATETIMEOFFSET",
                               Array.Empty <SqlExpression>(),
                               returnType));

                case nameof(DateTime.UtcNow):
                    var serverTranslation = _sqlExpressionFactory.Function(
                        declaringType == typeof(DateTime) ? "GETUTCDATE" : "SYSUTCDATETIME",
                        Array.Empty <SqlExpression>(),
                        returnType);

                    return(declaringType == typeof(DateTime)
                            ? (SqlExpression)serverTranslation
                            : _sqlExpressionFactory.Convert(serverTranslation, returnType));

                case nameof(DateTime.Today):
                    return(_sqlExpressionFactory.Function(
                               "CONVERT",
                               new SqlExpression[]
                    {
                        _sqlExpressionFactory.Fragment("date"),
                        _sqlExpressionFactory.Function(
                            "GETDATE",
                            Array.Empty <SqlExpression>(),
                            typeof(DateTime))
                    },
                               returnType));
                }
            }

            return(null);
        }
Example #12
0
        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 },
                            nullResultAllowed: false,
                            argumentsPropagateNullability: new[] { false },
                            returnType))
                },
                           null)
                    : (SqlExpression)_sqlExpressionFactory.Function(
                           functionName,
                           new[] { instance },
                           nullResultAllowed: true,
                           argumentsPropagateNullability: new[] { true },
                           returnType));
            }

            if (Equals(member, _geometryType))
            {
                return(_sqlExpressionFactory.Case(
                           _sqlExpressionFactory.Function(
                               "rtrim",
                               new SqlExpression[]
                {
                    _sqlExpressionFactory.Function(
                        "GeometryType",
                        new[] { instance },
                        nullResultAllowed: true,
                        argumentsPropagateNullability: new[] { true },
                        returnType),
                    _sqlExpressionFactory.Constant(" ZM")
                },
                               nullResultAllowed: true,
                               argumentsPropagateNullability: new[] { true },
                               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 },
                        nullResultAllowed: true,
                        argumentsPropagateNullability: new[] { true },
                        typeof(string)),
                    _sqlExpressionFactory.Constant(" ZM")
                },
                               nullResultAllowed: true,
                               argumentsPropagateNullability: new[] { true },
                               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);
        }
Example #13
0
 private SqlExpression TranslateSystemFunction(string function, Type returnType, params SqlExpression[] arguments)
 => _sqlExpressionFactory.Function(function, arguments, returnType);
        public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments)
        {
            if (_dateFromPartsMethodInfo.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           "DATEFROMPARTS",
                           arguments.Skip(1),
                           nullResultAllowed: true,
                           argumentsPropagateNullability: arguments.Skip(1).Select(a => true),
                           _dateFromPartsMethodInfo.ReturnType,
                           _typeMappingSource.FindMapping(typeof(DateTime), "date")));
            }

            if (_dateTimeFromPartsMethodInfo.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           "DATETIMEFROMPARTS",
                           arguments.Skip(1),
                           nullResultAllowed: true,
                           argumentsPropagateNullability: arguments.Skip(1).Select(a => true),
                           _dateTimeFromPartsMethodInfo.ReturnType,
                           _typeMappingSource.FindMapping(typeof(DateTime), "datetime")));
            }

            if (_dateTime2FromPartsMethodInfo.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           "DATETIME2FROMPARTS",
                           arguments.Skip(1),
                           nullResultAllowed: true,
                           argumentsPropagateNullability: arguments.Skip(1).Select(a => true),
                           _dateTime2FromPartsMethodInfo.ReturnType,
                           _typeMappingSource.FindMapping(typeof(DateTime), "datetime2")));
            }

            if (_dateTimeOffsetFromPartsMethodInfo.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           "DATETIMEOFFSETFROMPARTS",
                           arguments.Skip(1),
                           nullResultAllowed: true,
                           argumentsPropagateNullability: arguments.Skip(1).Select(a => true),
                           _dateTimeOffsetFromPartsMethodInfo.ReturnType,
                           _typeMappingSource.FindMapping(typeof(DateTimeOffset), "datetimeoffset")));
            }

            if (_smallDateTimeFromPartsMethodInfo.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           "SMALLDATETIMEFROMPARTS",
                           arguments.Skip(1),
                           nullResultAllowed: true,
                           argumentsPropagateNullability: arguments.Skip(1).Select(a => true),
                           _smallDateTimeFromPartsMethodInfo.ReturnType,
                           _typeMappingSource.FindMapping(typeof(DateTime), "smalldatetime")));
            }

            if (_timeFromPartsMethodInfo.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           "TIMEFROMPARTS",
                           arguments.Skip(1),
                           nullResultAllowed: true,
                           argumentsPropagateNullability: arguments.Skip(1).Select(a => true),
                           _timeFromPartsMethodInfo.ReturnType,
                           _typeMappingSource.FindMapping(typeof(TimeSpan), "time")));
            }

            return(null);
        }
Example #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 (_supportedMethodTranslations.TryGetValue(method, out var sqlFunctionName))
            {
                var typeMapping = arguments.Count == 1
                    ? ExpressionExtensions.InferTypeMapping(arguments[0])
                    : ExpressionExtensions.InferTypeMapping(arguments[0], arguments[1]);

                var newArguments = new SqlExpression[arguments.Count];
                newArguments[0] = _sqlExpressionFactory.ApplyTypeMapping(arguments[0], typeMapping);

                if (arguments.Count == 2)
                {
                    newArguments[1] = _sqlExpressionFactory.ApplyTypeMapping(arguments[1], typeMapping);
                }

                return(_sqlExpressionFactory.Function(
                           sqlFunctionName,
                           newArguments,
                           nullable: true,
                           argumentsPropagateNullability: newArguments.Select(a => true).ToArray(),
                           method.ReturnType,
                           sqlFunctionName == "SIGN" ? null : typeMapping));
            }

            if (_truncateMethodInfos.Contains(method))
            {
                var argument = arguments[0];

                return(_sqlExpressionFactory.Function(
                           "ROUND",
                           new[] { argument, _sqlExpressionFactory.Constant(0), _sqlExpressionFactory.Constant(1) },
                           nullable: true,
                           argumentsPropagateNullability: new[] { true, false, false },
                           method.ReturnType,
                           argument.TypeMapping));
            }

            if (_roundMethodInfos.Contains(method))
            {
                var argument = arguments[0];
                var digits   = arguments.Count == 2 ? arguments[1] : _sqlExpressionFactory.Constant(0);

                return(_sqlExpressionFactory.Function(
                           "ROUND",
                           new[] { argument, digits },
                           nullable: true,
                           argumentsPropagateNullability: new[] { true, true },
                           method.ReturnType,
                           argument.TypeMapping));
            }

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

            if (typeof(Geometry).IsAssignableFrom(method.DeclaringType))
            {
                var geometryExpressions = new[] { instance }.Concat(
                    arguments.Where(e => typeof(Geometry).IsAssignableFrom(e.Type)));
                var typeMapping = ExpressionExtensions.InferTypeMapping(geometryExpressions.ToArray());

                Check.DebugAssert(typeMapping != null, "At least one argument must have typeMapping.");
                var storeType   = typeMapping.StoreType;
                var isGeography = string.Equals(storeType, "geography", StringComparison.OrdinalIgnoreCase);

                if (_methodToFunctionName.TryGetValue(method, out var functionName) ||
                    (!isGeography && _geometryMethodToFunctionName.TryGetValue(method, out functionName)))
                {
                    instance = _sqlExpressionFactory.ApplyTypeMapping(
                        instance, _typeMappingSource.FindMapping(instance.Type, storeType));

                    var typeMappedArguments = new List <SqlExpression>();
                    foreach (var argument in arguments)
                    {
                        typeMappedArguments.Add(
                            _sqlExpressionFactory.ApplyTypeMapping(
                                argument,
                                typeof(Geometry).IsAssignableFrom(argument.Type)
                                    ? _typeMappingSource.FindMapping(argument.Type, storeType)
                                    : _typeMappingSource.FindMapping(argument.Type)));
                    }

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

                    return(_sqlExpressionFactory.Function(
                               instance,
                               functionName,
                               Simplify(typeMappedArguments, isGeography),
                               method.ReturnType,
                               resultTypeMapping));
                }

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

                if (Equals(method, _isWithinDistance))
                {
                    instance = _sqlExpressionFactory.ApplyTypeMapping(
                        instance, _typeMappingSource.FindMapping(instance.Type, storeType));

                    var typeMappedArguments = new List <SqlExpression>();
                    foreach (var argument in arguments)
                    {
                        typeMappedArguments.Add(
                            _sqlExpressionFactory.ApplyTypeMapping(
                                argument,
                                typeof(Geometry).IsAssignableFrom(argument.Type)
                                    ? _typeMappingSource.FindMapping(argument.Type, storeType)
                                    : _typeMappingSource.FindMapping(argument.Type)));
                    }

                    return(_sqlExpressionFactory.LessThanOrEqual(
                               _sqlExpressionFactory.Function(
                                   instance,
                                   "STDistance",
                                   Simplify(new[] { typeMappedArguments[0] }, isGeography),
                                   typeof(double)),
                               typeMappedArguments[1]));
                }
            }

            return(null);
        }
Example #17
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)
    {
        if (instance != null)
        {
            if (IndexOfMethodInfo.Equals(method))
            {
                var argument          = arguments[0];
                var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, argument);

                return(_sqlExpressionFactory.Subtract(
                           _sqlExpressionFactory.Function(
                               "instr",
                               new[]
                {
                    _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping),
                    _sqlExpressionFactory.ApplyTypeMapping(argument, stringTypeMapping)
                },
                               nullable: true,
                               argumentsPropagateNullability: new[] { true, true },
                               method.ReturnType),
                           _sqlExpressionFactory.Constant(1)));
            }

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

                return(_sqlExpressionFactory.Function(
                           "replace",
                           new[]
                {
                    _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping),
                    _sqlExpressionFactory.ApplyTypeMapping(firstArgument, stringTypeMapping),
                    _sqlExpressionFactory.ApplyTypeMapping(secondArgument, stringTypeMapping)
                },
                           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 (SubstringMethodInfoWithOneArg.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           "substr",
                           new[] { instance, _sqlExpressionFactory.Add(arguments[0], _sqlExpressionFactory.Constant(1)) },
                           nullable: true,
                           argumentsPropagateNullability: new[] { true, true },
                           method.ReturnType,
                           instance.TypeMapping));
            }

            if (SubstringMethodInfoWithTwoArgs.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           "substr",
                           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 ||
                TrimStartMethodInfoWithCharArg.Equals(method) == true ||
                TrimStartMethodInfoWithCharArrayArg.Equals(method))
            {
                return(ProcessTrimMethod(instance, arguments, "ltrim"));
            }

            if (TrimEndMethodInfoWithoutArgs.Equals(method) == true ||
                TrimEndMethodInfoWithCharArg.Equals(method) == true ||
                TrimEndMethodInfoWithCharArrayArg.Equals(method))
            {
                return(ProcessTrimMethod(instance, arguments, "rtrim"));
            }

            if (TrimMethodInfoWithoutArgs.Equals(method) == true ||
                TrimMethodInfoWithCharArg.Equals(method) == true ||
                TrimMethodInfoWithCharArrayArg.Equals(method))
            {
                return(ProcessTrimMethod(instance, arguments, "trim"));
            }

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

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

                return(_sqlExpressionFactory.OrElse(
                           _sqlExpressionFactory.Equal(
                               pattern,
                               _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)),
                           _sqlExpressionFactory.GreaterThan(
                               _sqlExpressionFactory.Function(
                                   "instr",
                                   new[] { instance, pattern },
                                   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 (IsNullOrWhiteSpaceMethodInfo.Equals(method))
        {
            var argument = arguments[0];

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

        if (FirstOrDefaultMethodInfoWithoutArgs.Equals(method))
        {
            var argument = arguments[0];
            return(_sqlExpressionFactory.Function(
                       "substr",
                       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(
                       "substr",
                       new[]
            {
                argument,
                _sqlExpressionFactory.Function(
                    "length",
                    new[] { argument },
                    nullable: true,
                    argumentsPropagateNullability: new[] { true },
                    typeof(int)),
                _sqlExpressionFactory.Constant(1)
            },
                       nullable: true,
                       argumentsPropagateNullability: new[] { true, true, true },
                       method.ReturnType));
        }

        return(null);
    }
 public virtual SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType)
 {
     return(Equals(member, _count)
         ? _sqlExpressionFactory.Function("NumGeometries", new[] { instance }, returnType)
         : 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)
        {
            Check.NotNull(member, nameof(member));
            Check.NotNull(returnType, nameof(returnType));
            Check.NotNull(logger, nameof(logger));

            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>(),
                               nullable: 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>(),
                                   nullable: true,
                                   instancePropagatesNullability: true,
                                   argumentsPropagateNullability: Array.Empty <bool>(),
                                   typeof(string)),
                               whenClauses,
                               null));
                }

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

            return(null);
        }
Example #20
0
        public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments, IDiagnosticsLogger <DbLoggerCategory.Query> logger)
        {
            method.ThrowIfNull(nameof(method));
            arguments.ThrowIfNull(nameof(arguments));
            logger.ThrowIfNull(nameof(logger));

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

                SqlExpression charIndexExpression;

                charIndexExpression = _sqlExpressionFactory.Function(
                    "AT",
                    new[] { argument, _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping) },
                    true,
                    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 },
                           true,
                           new[] { true, true, true },
                           method.ReturnType,
                           stringTypeMapping));
            }

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

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

            if (_substringNoLengthMethodInfo.Equals(method))
            {
                return(_sqlExpressionFactory.Function(
                           "SUBSTR",
                           new[]
                {
                    instance,
                    _sqlExpressionFactory.Add(arguments[0], _sqlExpressionFactory.Constant(1))
                },
                           true,
                           new[] { 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 },
                        true,
                        new[] { true },
                        argument.Type,
                        argument.TypeMapping)
                },
                                   true,
                                   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 },
                           true,
                           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 },
                           true,
                           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 },
                        true,
                        new[] { true },
                        instance.Type,
                        instance.TypeMapping)
                },
                           true,
                           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(
                                   "AT",
                                   new[] { pattern, instance },
                                   true,
                                   new[] { true, true },
                                   typeof(int)),
                               _sqlExpressionFactory.Constant(0)));
                }

                return(_sqlExpressionFactory.OrElse(
                           _sqlExpressionFactory.Equal(
                               pattern,
                               _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)),
                           _sqlExpressionFactory.GreaterThan(
                               _sqlExpressionFactory.Function(
                                   "AT",
                                   new[] { pattern, instance },
                                   true,
                                   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);
        }
    /// <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);
    }
Example #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, MethodInfo method, IReadOnlyList <SqlExpression> arguments)
        {
            Check.NotNull(method, nameof(method));
            Check.NotNull(arguments, nameof(arguments));

            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);
        }
Example #23
0
        public virtual SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType)
        {
            if (typeof(Geometry).IsAssignableFrom(member.DeclaringType))
            {
                Debug.Assert(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>(),
                               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>(),
                                   typeof(string)),
                               whenClauses.ToArray()));
                }

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

            return(null);
        }
Example #24
0
 public SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType)
 {
     return(_memberToFunctionName.TryGetValue(member, out var functionName)
         ? _sqlExpressionFactory.Function(functionName, new[] { instance }, returnType)
         : null);
 }
        public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments)
        {
            if (method == IndexOfString || method == IndexOfChar)
            {
                var argument          = arguments[0];
                var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, argument);

                return(_sqlExpressionFactory.Subtract(
                           _sqlExpressionFactory.Function(
                               "STRPOS",
                               new[]
                {
                    _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping),
                    _sqlExpressionFactory.ApplyTypeMapping(argument, stringTypeMapping)
                },
                               method.ReturnType),
                           _sqlExpressionFactory.Constant(1)));
            }

            if (method == Replace)
            {
                var oldValue          = arguments[0];
                var newValue          = arguments[1];
                var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, oldValue, newValue);

                return(_sqlExpressionFactory.Function(
                           "REPLACE",
                           new[]
                {
                    _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping),
                    _sqlExpressionFactory.ApplyTypeMapping(oldValue, stringTypeMapping),
                    _sqlExpressionFactory.ApplyTypeMapping(newValue, stringTypeMapping)
                },
                           method.ReturnType,
                           stringTypeMapping));
            }

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

            if (method == Substring || method == SubstringWithLength)
            {
                var args =
                    method == Substring
                        ? new[] { instance, GenerateOneBasedIndexExpression(arguments[0]) }
                        : new[] { instance, GenerateOneBasedIndexExpression(arguments[0]), arguments[1] };
                return(_sqlExpressionFactory.Function(
                           "SUBSTRING",
                           args,
                           method.ReturnType,
                           instance.TypeMapping));
            }

            if (method == IsNullOrWhiteSpace)
            {
                var argument = arguments[0];

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

            var isTrimStart = method == TrimStartWithNoParam || method == TrimStartWithChars || method == TrimStartWithSingleChar;
            var isTrimEnd   = method == TrimEndWithNoParam || method == TrimEndWithChars || method == TrimEndWithSingleChar;
            var isTrimBoth  = method == TrimBothWithNoParam || method == TrimBothWithChars || method == TrimBothWithSingleChar;

            if (isTrimStart || isTrimEnd || isTrimBoth)
            {
                char[] trimChars = null;

                if (method == TrimStartWithChars || method == TrimStartWithSingleChar ||
                    method == TrimEndWithChars || method == TrimEndWithSingleChar ||
                    method == TrimBothWithChars || method == TrimBothWithSingleChar)
                {
                    var constantTrimChars = arguments[0] as SqlConstantExpression;
                    if (constantTrimChars == null)
                    {
                        return(null); // Don't translate if trim chars isn't a constant
                    }
                    trimChars = constantTrimChars.Value is char c
                        ? new[] { c }
                        : (char[])constantTrimChars.Value;
                }

                return(_sqlExpressionFactory.Function(
                           isTrimStart ? "LTRIM" : isTrimEnd ? "RTRIM" : "BTRIM",
                           new[]
                {
                    instance,
                    trimChars == null || trimChars.Length == 0
                            ? _whitespace
                            : _sqlExpressionFactory.Constant(new string(trimChars))
                },
                           instance.Type,
                           instance.TypeMapping));
            }

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

                var strposCheck = _sqlExpressionFactory.GreaterThan(
                    _sqlExpressionFactory.Function(
                        "STRPOS",
                        new[]
                {
                    _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping),
                    _sqlExpressionFactory.ApplyTypeMapping(pattern, stringTypeMapping)
                },
                        typeof(int)),
                    _sqlExpressionFactory.Constant(0));

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

                return(_sqlExpressionFactory.OrElse(
                           _sqlExpressionFactory.Equal(
                               pattern,
                               _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)),
                           strposCheck));
            }

            if (method == PadLeft || method == PadLeftWithChar || method == PadRight || method == PadRightWithChar)
            {
                var args =
                    method == PadLeft || method == PadRight
                        ? new[] { instance, arguments[0] }
                        : new[] { instance, arguments[0], arguments[1] };

                return(_sqlExpressionFactory.Function(
                           method == PadLeft || method == PadLeftWithChar ? "lpad" : "rpad",
                           args,
                           instance.Type,
                           instance.TypeMapping));
            }

            if (method == StartsWith)
            {
                return(TranslateStartsEndsWith(instance, arguments[0], true));
            }
            if (method == EndsWith)
            {
                return(TranslateStartsEndsWith(instance, arguments[0], false));
            }

            return(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);
        }
        public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments, IDiagnosticsLogger <DbLoggerCategory.Query> logger)
        {
            if (_methodInfoDateAddMapping != null && _methodInfoDateAddMapping.TryGetValue(method, out var dateAddPart))
            {
                return(arguments[0] is SqlConstantExpression sqlConstant &&
                       ((sqlConstant.Value is double && ((double)sqlConstant.Value >= int.MaxValue || (double)sqlConstant.Value <= int.MinValue)) ||
                        (sqlConstant.Value is long && ((long)sqlConstant.Value >= int.MaxValue || (long)sqlConstant.Value <= int.MinValue)))
                        ? null
                        : _sqlExpressionFactory.Function(
                           "DATEADD",
                           new[]
                {
                    _sqlExpressionFactory.Fragment(dateAddPart),
                    _sqlExpressionFactory.Convert(arguments[0], typeof(int)),
                    instance
                },
                           instance.Type,
                           instance.TypeMapping));
            }
            else if (_methodInfoDateAddExtensionMapping != null && _methodInfoDateAddExtensionMapping.TryGetValue(method, out var dateAddExtensionPart))
            {
                return(arguments[1] is SqlConstantExpression sqlConstant &&
                       ((sqlConstant.Value is double && ((double)sqlConstant.Value >= int.MaxValue || (double)sqlConstant.Value <= int.MinValue)) ||
                        (sqlConstant.Value is long && ((long)sqlConstant.Value >= int.MaxValue || (long)sqlConstant.Value <= int.MinValue)))
                        ? null
                        : _sqlExpressionFactory.Function(
                           "DATEADD",
                           new[]
                {
                    _sqlExpressionFactory.Fragment(dateAddExtensionPart),
                    _sqlExpressionFactory.Convert(arguments[1], typeof(int)),
                    arguments[0]
                },
                           arguments[0].Type,
                           arguments[0].TypeMapping));
            }
            else if (_methodInfoDatePartExtensionMapping != null && _methodInfoDatePartExtensionMapping.TryGetValue(method, out var datePart))
            {
                return(_sqlExpressionFactory.Function(
                           "DATEPART",
                           new[]
                {
                    _sqlExpressionFactory.Fragment(datePart),
                    arguments[0]
                },
                           method.ReturnType,
                           null));
            }
            else if (_methodInfoDateDiffMapping != null && _methodInfoDateDiffMapping.TryGetValue(method, out var dateDiffDatePart))
            {
                var startDate   = arguments[1];
                var endDate     = arguments[2];
                var typeMapping = ExpressionExtensions.InferTypeMapping(startDate, endDate);

                startDate = _sqlExpressionFactory.ApplyTypeMapping(startDate, typeMapping);
                endDate   = _sqlExpressionFactory.ApplyTypeMapping(endDate, typeMapping);

                return(_sqlExpressionFactory.Function(
                           "DATEDIFF",
                           new[] { _sqlExpressionFactory.Fragment(dateDiffDatePart), startDate, endDate },
                           method.ReturnType,
                           null));
            }
            else if (_methodInfoDateDiffBigMapping != null && _methodInfoDateDiffBigMapping.TryGetValue(method, out var dateDiffBigDatePart))
            {
                var startDate   = arguments[1];
                var endDate     = arguments[2];
                var typeMapping = ExpressionExtensions.InferTypeMapping(startDate, endDate);

                startDate = _sqlExpressionFactory.ApplyTypeMapping(startDate, typeMapping);
                endDate   = _sqlExpressionFactory.ApplyTypeMapping(endDate, typeMapping);

                return(_sqlExpressionFactory.Function(
                           "DATEDIFF_BIG",
                           new[] { _sqlExpressionFactory.Fragment(dateDiffBigDatePart), startDate, endDate },
                           method.ReturnType,
                           null));
            }
            return(null);
        }
 public override SqlExpression TranslateLongCount(Expression expression = null)
 {
     // TODO: Translate Count with predicate for GroupBy
     return(_sqlExpressionFactory.ApplyDefaultTypeMapping(
                _sqlExpressionFactory.Function("COUNT_BIG", new[] { _sqlExpressionFactory.Fragment("*") }, typeof(long))));
 }
        /// <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 (typeof(Geometry).IsAssignableFrom(method.DeclaringType) &&
                instance != null)
            {
                var geometryExpressions = new[] { instance }.Concat(
                    arguments.Where(e => typeof(Geometry).IsAssignableFrom(e.Type)));
                var typeMapping = ExpressionExtensions.InferTypeMapping(geometryExpressions.ToArray());

                Check.DebugAssert(typeMapping != null, "At least one argument must have typeMapping.");
                var storeType   = typeMapping.StoreType;
                var isGeography = string.Equals(storeType, "geography", StringComparison.OrdinalIgnoreCase);

                if (_methodToFunctionName.TryGetValue(method, out var functionName) ||
                    (!isGeography && _geometryMethodToFunctionName.TryGetValue(method, out functionName)))
                {
                    instance = _sqlExpressionFactory.ApplyTypeMapping(
                        instance, _typeMappingSource.FindMapping(instance.Type, storeType));

                    var typeMappedArguments = new List <SqlExpression>();
                    foreach (var argument in arguments)
                    {
                        typeMappedArguments.Add(
                            _sqlExpressionFactory.ApplyTypeMapping(
                                argument,
                                typeof(Geometry).IsAssignableFrom(argument.Type)
                                    ? _typeMappingSource.FindMapping(argument.Type, storeType)
                                    : _typeMappingSource.FindMapping(argument.Type)));
                    }

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

                    var finalArguments = Simplify(typeMappedArguments, isGeography);

                    var argumentsPropagateNullability = functionName == "STBuffer"
                        ? new[] { false }
                        : functionName == "STRelate"
                            ? new[] { true, false }
                            : finalArguments.Select(a => true).ToArray();

                    return(_sqlExpressionFactory.Function(
                               instance,
                               functionName,
                               finalArguments,
                               nullable: true,
                               instancePropagatesNullability: true,
                               argumentsPropagateNullability,
                               method.ReturnType,
                               resultTypeMapping));
                }

                if (Equals(method, _getGeometryN))
                {
                    return(_sqlExpressionFactory.Function(
                               instance,
                               "STGeometryN",
                               new[]
                    {
                        _sqlExpressionFactory.Add(
                            arguments[0],
                            _sqlExpressionFactory.Constant(1))
                    },
                               nullable: true,
                               instancePropagatesNullability: true,
                               argumentsPropagateNullability: new[] { false },
                               method.ReturnType,
                               _typeMappingSource.FindMapping(method.ReturnType, storeType)));
                }

                if (Equals(method, _isWithinDistance))
                {
                    instance = _sqlExpressionFactory.ApplyTypeMapping(
                        instance, _typeMappingSource.FindMapping(instance.Type, storeType));

                    var typeMappedArguments = new List <SqlExpression>();
                    foreach (var argument in arguments)
                    {
                        typeMappedArguments.Add(
                            _sqlExpressionFactory.ApplyTypeMapping(
                                argument,
                                typeof(Geometry).IsAssignableFrom(argument.Type)
                                    ? _typeMappingSource.FindMapping(argument.Type, storeType)
                                    : _typeMappingSource.FindMapping(argument.Type)));
                    }

                    var finalArguments = Simplify(new[] { typeMappedArguments[0] }, isGeography);

                    return(_sqlExpressionFactory.LessThanOrEqual(
                               _sqlExpressionFactory.Function(
                                   instance,
                                   "STDistance",
                                   finalArguments,
                                   nullable: true,
                                   instancePropagatesNullability: true,
                                   argumentsPropagateNullability: finalArguments.Select(a => true),
                                   typeof(double)),
                               typeMappedArguments[1]));
                }
            }

            return(null);
        }
Example #30
0
        /// <inheritdoc />
        public virtual SqlExpression Translate(
            SqlExpression instance,
            MethodInfo method,
            IReadOnlyList <SqlExpression> arguments,
            IDiagnosticsLogger <DbLoggerCategory.Query> logger)
        {
            if (SupportedMethodTranslations.TryGetValue(method, out var sqlFunctionName))
            {
                var typeMapping = arguments.Count == 1
                    ? ExpressionExtensions.InferTypeMapping(arguments[0])
                    : ExpressionExtensions.InferTypeMapping(arguments[0], arguments[1]);

                var newArguments = new SqlExpression[arguments.Count];
                newArguments[0] = _sqlExpressionFactory.ApplyTypeMapping(arguments[0], typeMapping);

                if (arguments.Count == 2)
                {
                    newArguments[1] = _sqlExpressionFactory.ApplyTypeMapping(arguments[1], typeMapping);
                }

                // Note: GREATER/LEAST only return NULL if *all* arguments are null, but we currently can't
                // convey this.
                return(_sqlExpressionFactory.Function(
                           sqlFunctionName,
                           newArguments,
                           nullable: true,
                           argumentsPropagateNullability: TrueArrays[newArguments.Length],
                           method.ReturnType,
                           typeMapping));
            }

            // PostgreSQL sign() returns 1, 0, -1, but in the same type as the argument, so we need to convert
            // the return type to int.
            if (SignMethodInfos.Contains(method))
            {
                return
                    (_sqlExpressionFactory.Convert(
                         _sqlExpressionFactory.Function(
                             "sign",
                             arguments,
                             nullable: true,
                             argumentsPropagateNullability: TrueArrays[1],
                             method.ReturnType),
                         typeof(int),
                         _typeMappingSource.FindMapping(typeof(int))));
            }

            if (method == RoundDecimalTwoParams)
            {
                return(_sqlExpressionFactory.Function("round", new[]
                {
                    _sqlExpressionFactory.ApplyDefaultTypeMapping(arguments[0]),
                    _sqlExpressionFactory.ApplyDefaultTypeMapping(arguments[1])
                },
                                                      nullable: true,
                                                      argumentsPropagateNullability: TrueArrays[2],
                                                      method.ReturnType,
                                                      _typeMappingSource.FindMapping(typeof(decimal))));
            }

            // PostgreSQL treats NaN values as equal, against IEEE754
            if (method == DoubleIsNanMethodInfo)
            {
                return(_sqlExpressionFactory.Equal(arguments[0], _sqlExpressionFactory.Constant(double.NaN)));
            }
            if (method == FloatIsNanMethodInfo)
            {
                return(_sqlExpressionFactory.Equal(arguments[0], _sqlExpressionFactory.Constant(float.NaN)));
            }
            if (method == DoubleIsPositiveInfinityMethodInfo)
            {
                return(_sqlExpressionFactory.Equal(arguments[0], _sqlExpressionFactory.Constant(double.PositiveInfinity)));
            }
            if (method == FloatIsPositiveInfinityMethodInfo)
            {
                return(_sqlExpressionFactory.Equal(arguments[0], _sqlExpressionFactory.Constant(float.PositiveInfinity)));
            }
            if (method == DoubleIsNegativeInfinityMethodInfo)
            {
                return(_sqlExpressionFactory.Equal(arguments[0], _sqlExpressionFactory.Constant(double.NegativeInfinity)));
            }
            if (method == FloatIsNegativeInfinityMethodInfo)
            {
                return(_sqlExpressionFactory.Equal(arguments[0], _sqlExpressionFactory.Constant(float.NegativeInfinity)));
            }

            return(null);
        }