protected override ShapedQueryExpression TranslateCount(ShapedQueryExpression source, LambdaExpression predicate)
        {
            var selectExpression = (SelectExpression)source.QueryExpression;

            if (selectExpression.IsDistinct ||
                selectExpression.Limit != null ||
                selectExpression.Offset != null)
            {
                selectExpression.PushdownIntoSubQuery();
            }

            if (predicate != null)
            {
                source = TranslateWhere(source, predicate);
            }

            var translation = _sqlExpressionFactory.ApplyDefaultTypeMapping(
                _sqlExpressionFactory.Function("COUNT", new[] { _sqlExpressionFactory.Fragment("*") }, typeof(int)));

            var _projectionMapping = new Dictionary <ProjectionMember, Expression>
            {
                { new ProjectionMember(), translation }
            };

            selectExpression.ClearOrdering();
            selectExpression.ReplaceProjection(_projectionMapping);
            source.ShaperExpression = new ProjectionBindingExpression(source.QueryExpression, new ProjectionMember(), typeof(int));

            return(source);
        }
Esempio n. 2
0
        protected override ShapedQueryExpression TranslateCount(ShapedQueryExpression source, LambdaExpression predicate)
        {
            var selectExpression = (SelectExpression)source.QueryExpression;

            selectExpression.PrepareForAggregate();

            if (predicate != null)
            {
                source = TranslateWhere(source, predicate);
            }

            var translation = _sqlExpressionFactory.ApplyDefaultTypeMapping(
                _sqlExpressionFactory.Function("COUNT", new[] { _sqlExpressionFactory.Fragment("*") }, typeof(int)));

            var projectionMapping = new Dictionary <ProjectionMember, Expression>
            {
                { new ProjectionMember(), translation }
            };

            selectExpression.ClearOrdering();
            selectExpression.ReplaceProjectionMapping(projectionMapping);
            source.ShaperExpression = new ProjectionBindingExpression(source.QueryExpression, new ProjectionMember(), typeof(int));

            return(source);
        }
Esempio n. 3
0
 internal SpannerIntervalExpression(ISqlExpressionFactory sqlExpressionFactory, SqlExpression value, string intervalName) : base(value.Type, value.TypeMapping)
 {
     _sqlExpressionFactory = sqlExpressionFactory;
     _intervalName         = intervalName;
     _value                = value;
     _intervalFragment     = _sqlExpressionFactory.Fragment("INTERVAL ");
     _intervalNameFragment = _sqlExpressionFactory.Fragment($" {_intervalName}");
 }
 internal SpannerTimestampExtractExpression(ISqlExpressionFactory sqlExpressionFactory, SqlExpression value, string dateTimePartName) : base(value.Type, value.TypeMapping)
 {
     _sqlExpressionFactory = sqlExpressionFactory;
     _dateTimePartName     = dateTimePartName;
     _value            = value;
     _fromFragment     = _sqlExpressionFactory.Fragment($"{_dateTimePartName} FROM ");
     _timezoneFragment = _sqlExpressionFactory.Fragment(" AT TIME ZONE 'UTC'");
 }
        public virtual SqlExpression TranslateCount([CanBeNull] Expression expression = null)
        {
            if (expression != null)
            {
                // TODO: Translate Count with predicate for GroupBy
                return(null);
            }

            return(_sqlExpressionFactory.ApplyDefaultTypeMapping(
                       _sqlExpressionFactory.Function("COUNT", new[] { _sqlExpressionFactory.Fragment("*") }, typeof(int))));
        }
Esempio n. 6
0
        public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments)
        {
            Check.NotNull(method, nameof(method));
            Check.NotNull(arguments, nameof(arguments));

            if (_methodInfoDatePartMapping.TryGetValue(method, out var datePart))
            {
                return(!datePart.Equals("year") &&
                       !datePart.Equals("month") &&
                       arguments[0] is SqlConstantExpression sqlConstant &&
                       ((double)sqlConstant.Value >= int.MaxValue ||
                        (double)sqlConstant.Value <= int.MinValue)
                        ? null
                        : _sqlExpressionFactory.Function(
                           "DATEADD",
                           new[]
                {
                    _sqlExpressionFactory.Fragment(datePart),
                    _sqlExpressionFactory.Convert(arguments[0], typeof(int)),
                    instance
                },
                           instance.Type,
                           instance.TypeMapping));
            }

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

            if (_methodInfoDatePartMapping.TryGetValue(method, out var datePart))
            {
                // DateAdd does not accept number argument outside of int range
                // AddYears/AddMonths take int argument so no need to check for range
                return(!datePart.Equals("year") &&
                       !datePart.Equals("month") &&
                       arguments[0] is SqlConstantExpression sqlConstant &&
                       ((double)sqlConstant.Value >= int.MaxValue ||
                        (double)sqlConstant.Value <= int.MinValue)
                        ? null
                        : _sqlExpressionFactory.Function(
                           "DATEADD",
                           new[]
                {
                    _sqlExpressionFactory.Fragment(datePart),
                    _sqlExpressionFactory.Convert(arguments[0], typeof(int)),
                    instance
                },
                           nullable: true,
                           argumentsPropagateNullability: new[] { false, true, true },
                           instance.Type,
                           instance.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 (_functionMapping.TryGetValue(method, out var functionName))
            {
                var propertyReference = arguments[1];
                if (!(propertyReference is ColumnExpression))
                {
                    throw new InvalidOperationException(SqlServerStrings.InvalidColumnNameForFreeText);
                }

                var typeMapping = propertyReference.TypeMapping;
                var freeText    = _sqlExpressionFactory.ApplyTypeMapping(arguments[2], typeMapping);

                var functionArguments = new List <SqlExpression> {
                    propertyReference, freeText
                };

                if (arguments.Count == 4)
                {
                    functionArguments.Add(
                        _sqlExpressionFactory.Fragment($"LANGUAGE {((SqlConstantExpression)arguments[3]).Value}"));
                }

                return(_sqlExpressionFactory.Function(
                           functionName,
                           functionArguments,
                           typeof(bool)));
            }

            return(null);
        }
Esempio n. 9
0
        public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments)
        {
            if (_functionMapping.TryGetValue(method, out var functionName))
            {
                var propertyReference = arguments[1];
                if (!(propertyReference is ColumnExpression))
                {
                    throw new InvalidOperationException("The 'FreeText' method is not supported because the query has switched to client-evaluation. Inspect the log to determine which query expressions are triggering client-evaluation.");
                }

                var typeMapping = propertyReference.TypeMapping;
                var freeText    = _sqlExpressionFactory.ApplyTypeMapping(arguments[2], typeMapping);

                var functionArguments = new List <SqlExpression> {
                    propertyReference, freeText
                };

                if (arguments.Count == 4)
                {
                    functionArguments.Add(
                        _sqlExpressionFactory.Fragment($"LANGUAGE {((SqlConstantExpression)arguments[3]).Value}"));
                }

                return(_sqlExpressionFactory.Function(
                           functionName,
                           functionArguments,
                           typeof(bool)));
            }

            return(null);
        }
Esempio n. 10
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 (_methodInfoDateDiffMapping.TryGetValue(method, out var datePart))
            {
                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(datePart), startDate, endDate },
                           nullable: true,
                           argumentsPropagateNullability: new[] { false, true, true },
                           typeof(int)));
            }

            return(null);
        }
 internal SpannerDateExtractExpression(ISqlExpressionFactory sqlExpressionFactory, SqlExpression value, string dateTimePartName)
     : base(value.Type, value.TypeMapping)
 {
     _sqlExpressionFactory = sqlExpressionFactory;
     _dateTimePartName     = dateTimePartName;
     _value        = value;
     _fromFragment = _sqlExpressionFactory.Fragment($"{_dateTimePartName} FROM ");
 }
Esempio n. 12
0
 public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments)
 {
     return(_supportedMethods.Contains(method)
         ? _sqlExpressionFactory.Function(
                "CONVERT",
                new[] { _sqlExpressionFactory.Fragment(_typeMapping[method.Name]), arguments[0] },
                method.ReturnType)
         : null);
 }
 private IEnumerable <SqlExpression> simplify(IEnumerable <SqlExpression> arguments)
 {
     foreach (var argument in arguments)
     {
         if (argument is SqlConstantExpression constant &&
             constant.Value is HierarchyId hierarchyId)
         {
             yield return(_sqlExpressionFactory.Fragment($"'{hierarchyId}'"));
         }
        public override SqlExpression TranslateLongCount(Expression expression = null)
        {
            if (expression != null)
            {
                // TODO: Translate Count with predicate for GroupBy
                return(null);
            }

            return(_sqlExpressionFactory.ApplyDefaultTypeMapping(
                       _sqlExpressionFactory.Function("COUNT_BIG", new[] { _sqlExpressionFactory.Fragment("*") }, typeof(long))));
        }
Esempio n. 15
0
        /// <inheritdoc />
        public virtual SqlExpression Translate(
            SqlExpression instance,
            MethodInfo method,
            IReadOnlyList <SqlExpression> arguments,
            IDiagnosticsLogger <DbLoggerCategory.Query> logger)
        {
            if (!MethodInfoDatePartMapping.TryGetValue(method, out var datePart))
            {
                return(null);
            }

            var interval = arguments[0];

            if (instance is null || interval is null)
            {
                return(null);
            }

            // Note: ideally we'd simply generate a PostgreSQL interval expression, but the .NET mapping of that is TimeSpan,
            // which does not work for months, years, etc. So we generate special fragments instead.
            if (interval is SqlConstantExpression constantExpression)
            {
                // We generate constant intervals as INTERVAL '1 days'
                if (constantExpression.Type == typeof(double) &&
                    ((double)constantExpression.Value >= int.MaxValue ||
                     (double)constantExpression.Value <= int.MinValue))
                {
                    return(null);
                }

                interval = _sqlExpressionFactory.Fragment(FormattableString.Invariant($"INTERVAL '{constantExpression.Value} {datePart}'"));
            }
            else
            {
                // For non-constants, we can't parameterize INTERVAL '1 days'. Instead, we use CAST($1 || ' days' AS interval).
                // Note that a make_interval() function also exists, but accepts only int (for all fields except for
                // seconds), so we don't use it.
                // Note: we instantiate SqlBinaryExpression manually rather than via sqlExpressionFactory because
                // of the non-standard Add expression (concatenate int with text)
                interval = _sqlExpressionFactory.Convert(
                    new SqlBinaryExpression(
                        ExpressionType.Add,
                        _sqlExpressionFactory.Convert(interval, typeof(string), _textMapping),
                        _sqlExpressionFactory.Constant(' ' + datePart, _textMapping),
                        typeof(string),
                        _textMapping),
                    typeof(TimeSpan),
                    _intervalMapping);
            }

            return(_sqlExpressionFactory.Add(instance, interval, instance.TypeMapping));
        }
Esempio n. 16
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));

            return(_supportedMethods.Contains(method)
                ? _sqlExpressionFactory.Function(
                       "CONVERT",
                       new[] { _sqlExpressionFactory.Fragment(_typeMapping[method.Name]), arguments[0] },
                       nullable: true,
                       argumentsPropagateNullability: new[] { false, true },
                       method.ReturnType)
                : null);
        }
 public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments)
 {
     return(method.Name == nameof(ToString) &&
            arguments.Count == 0 &&
            instance != null &&
            _typeMapping.TryGetValue(
                instance.Type.UnwrapNullableType(),
                out var storeType)
         ? _sqlExpressionFactory.Function(
                "CONVERT",
                new[] { _sqlExpressionFactory.Fragment(storeType), instance },
                typeof(string))
         : null);
 }
        private IEnumerable <SqlExpression> Simplify(IEnumerable <SqlExpression> arguments, bool isGeography)
        {
            foreach (var argument in arguments)
            {
                if (argument is SqlConstantExpression constant &&
                    constant.Value is Geometry geometry &&
                    geometry.SRID == (isGeography ? 4326 : 0))
                {
                    yield return(_sqlExpressionFactory.Fragment("'" + geometry.AsText() + "'"));

                    continue;
                }

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

            if (member.DeclaringType == typeof(TimeSpan) && _datePartMappings.TryGetValue(member.Name, out string value))
            {
                return(_sqlExpressionFactory.Function("DATEPART", new []
                {
                    _sqlExpressionFactory.Fragment(value),
                    instance
                }, returnType));
            }

            return(null);
        }
Esempio n. 20
0
        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 (_methodInfoDatePartMapping.TryGetValue(method, out var datePart) &&
                instance != null)
            {
                // DateAdd does not accept number argument outside of int range
                // AddYears/AddMonths take int argument so no need to check for range
                if (datePart != "year" &&
                    datePart != "month" &&
                    arguments[0] is SqlConstantExpression sqlConstant &&
                    sqlConstant.Value is double doubleValue &&
                    (doubleValue >= int.MaxValue ||
                     doubleValue <= int.MinValue))
                {
                    return(null);
                }

                if (instance is SqlConstantExpression instanceConstant)
                {
                    instance = instanceConstant.ApplyTypeMapping(_typeMappingSource.FindMapping(typeof(DateTime), "datetime"));
                }

                return(_sqlExpressionFactory.Function(
                           "DATEADD",
                           new[]
                {
                    _sqlExpressionFactory.Fragment(datePart),
                    _sqlExpressionFactory.Convert(arguments[0], typeof(int)),
                    instance
                },
                           nullable: true,
                           argumentsPropagateNullability: new[] { false, true, true },
                           instance.Type,
                           instance.TypeMapping));
            }

            return(null);
        }
Esempio n. 21
0
        public SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType)
        {
            if (member.DeclaringType == this._declaringType)
            {
                var memberName = member.Name;

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

            return(null);
        }
Esempio n. 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));

            return(method.Name == nameof(ToString) &&
                   arguments.Count == 0 &&
                   instance != null &&
                   _typeMapping.TryGetValue(instance.Type, out var storeType)
                ? _sqlExpressionFactory.Function(
                       "CONVERT",
                       new[] { _sqlExpressionFactory.Fragment(storeType), instance },
                       nullable: true,
                       argumentsPropagateNullability: new bool[] { false, true },
                       typeof(string))
                : null);
        }
        /// <summary>
        ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
        ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
        ///     any release. You should only use it directly in your code with extreme caution and knowing that
        ///     doing so can result in application failures when updating to a new Entity Framework Core release.
        /// </summary>
        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 (_functionMapping.TryGetValue(method, out var functionName))
            {
                var propertyReference = arguments[1];
                if (!(propertyReference is ColumnExpression))
                {
                    throw new InvalidOperationException(SqlServerStrings.InvalidColumnNameForFreeText);
                }

                var typeMapping = propertyReference.TypeMapping;
                var freeText    = propertyReference.Type == arguments[2].Type
                    ? _sqlExpressionFactory.ApplyTypeMapping(arguments[2], typeMapping)
                    : _sqlExpressionFactory.ApplyDefaultTypeMapping(arguments[2]);

                var functionArguments = new List <SqlExpression> {
                    propertyReference, freeText
                };

                if (arguments.Count == 4)
                {
                    functionArguments.Add(
                        _sqlExpressionFactory.Fragment($"LANGUAGE {((SqlConstantExpression)arguments[3]).Value}"));
                }

                return(_sqlExpressionFactory.Function(
                           functionName,
                           functionArguments,
                           nullable: true,
                           // TODO: don't propagate for now
                           argumentsPropagateNullability: functionArguments.Select(a => false).ToList(),
                           typeof(bool)));
            }

            return(null);
        }
        public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments)
        {
            if (_methodInfoDateDiffMapping.TryGetValue(method, out var datePart))
            {
                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(datePart), startDate, endDate },
                           typeof(int)));
            }

            return(null);
        }
 public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments, IDiagnosticsLogger <DbLoggerCategory.Query> logger)
 {
     // Translates parameterless Object.ToString() calls.
     return(method.Name == nameof(ToString) &&
            arguments.Count == 0 &&
            instance != null &&
            _typeMapping.TryGetValue(
                instance.Type
                .UnwrapNullableType(),
                out var storeType)
   ? _sqlExpressionFactory.Function(
                "CONVERT",
                new[]
     {
         instance,
         _sqlExpressionFactory.Fragment(storeType)
     },
                typeof(string))
   : null);
 }
        /// <summary>
        ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
        ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
        ///     any release. You should only use it directly in your code with extreme caution and knowing that
        ///     doing so can result in application failures when updating to a new Entity Framework Core release.
        /// </summary>
        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 (member.DeclaringType == typeof(TimeSpan) && _datePartMappings.TryGetValue(member.Name, out string value))
            {
                return(_sqlExpressionFactory.Function(
                           "DATEPART", new[] { _sqlExpressionFactory.Fragment(value), instance },
                           nullable: true,
                           argumentsPropagateNullability: new[] { false, true },
                           returnType));
            }

            return(null);
        }
        private SqlExpression GetFirstArgumentAsInt64(IReadOnlyList <SqlExpression> arguments, long multiplier)
        {
            SqlExpression value = _sqlExpressionFactory.ApplyDefaultTypeMapping(arguments[0]);

            if (value.TypeMapping != null && value.TypeMapping.StoreTypeNameBase == "FLOAT64")
            {
                value = _sqlExpressionFactory.ApplyDefaultTypeMapping(_sqlExpressionFactory.Function("CAST", new[] { value, _sqlExpressionFactory.Fragment("INT64") }, typeof(long)));
            }
            if (multiplier != 1L)
            {
                value = _sqlExpressionFactory.Multiply(_sqlExpressionFactory.Constant(multiplier), value, value.TypeMapping);
            }
            return(value);
        }
        public virtual SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType)
        {
            Check.NotNull(member, nameof(member));
            Check.NotNull(returnType, nameof(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);
        }
        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);
        }
        /// <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.Function(
                               "CONVERT",
                               new[] { _sqlExpressionFactory.Fragment("time"), instance },
                               nullable: true,
                               argumentsPropagateNullability: new[] { false, true },
                               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);
        }