private static bool TryTranslateDateTimeProperty(MemberExpression expression, AggregationExpression container, MemberInfo memberInfo, out AggregationExpression result)
        {
            result = null;

            if (container.Expression.Type == typeof(DateTime) && memberInfo is PropertyInfo propertyInfo)
            {
                AstExpression   ast;
                IBsonSerializer serializer;

                if (propertyInfo.Name == "DayOfWeek")
                {
                    ast        = AstExpression.Subtract(AstExpression.DatePart(AstDatePart.DayOfWeek, container.Ast), 1);
                    serializer = new EnumSerializer <DayOfWeek>(BsonType.Int32);
                }
                else
                {
                    AstDatePart datePart;
                    switch (propertyInfo.Name)
                    {
                    case "Day": datePart = AstDatePart.DayOfMonth; break;

                    case "DayOfWeek": datePart = AstDatePart.DayOfWeek; break;

                    case "DayOfYear": datePart = AstDatePart.DayOfYear; break;

                    case "Hour": datePart = AstDatePart.Hour; break;

                    case "Millisecond": datePart = AstDatePart.Millisecond; break;

                    case "Minute": datePart = AstDatePart.Minute; break;

                    case "Month": datePart = AstDatePart.Month; break;

                    case "Second": datePart = AstDatePart.Second; break;

                    case "Week": datePart = AstDatePart.Week; break;

                    case "Year": datePart = AstDatePart.Year; break;

                    default: return(false);
                    }
                    ast        = AstExpression.DatePart(datePart, container.Ast);
                    serializer = new Int32Serializer();
                }

                result = new AggregationExpression(expression, ast, serializer);
                return(true);
            }

            return(false);
        }
        public static AggregationExpression Translate(TranslationContext context, MemberExpression expression)
        {
            var containerExpression = expression.Expression;
            var member = expression.Member;

            if (member is PropertyInfo property)
            {
                switch (property.Name)
                {
                case "HasValue": return(HasValuePropertyToAggregationExpressionTranslator.Translate(context, expression));

                case "Value": return(ValuePropertyToAggregationExpressionTranslator.Translate(context, expression));

                default: break;
                }
            }

            var containerTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, containerExpression);

            if (containerTranslation.Serializer is IWrappedValueSerializer wrappedValueSerializer)
            {
                var unwrappedValueAst = AstExpression.GetField(containerTranslation.Ast, wrappedValueSerializer.FieldName);
                containerTranslation = new AggregationExpression(expression, unwrappedValueAst, wrappedValueSerializer.ValueSerializer);
            }

            if (!DocumentSerializerHelper.HasFieldInfo(containerTranslation.Serializer, member.Name))
            {
                if (member is PropertyInfo propertyInfo && propertyInfo.Name == "Length")
                {
                    return(LengthPropertyToAggregationExpressionTranslator.Translate(context, expression));
                }

                if (TryTranslateCollectionCountProperty(expression, containerTranslation, member, out var translatedCount))
                {
                    return(translatedCount);
                }

                if (TryTranslateDateTimeProperty(expression, containerTranslation, member, out var translatedDateTimeProperty))
                {
                    return(translatedDateTimeProperty);
                }
            }

            var fieldInfo = DocumentSerializerHelper.GetFieldInfo(containerTranslation.Serializer, member.Name);
            var ast       = AstExpression.GetField(containerTranslation.Ast, fieldInfo.ElementName);

            return(new AggregationExpression(expression, ast, fieldInfo.Serializer));
        }
        private static bool TryTranslateCollectionCountProperty(MemberExpression expression, AggregationExpression container, MemberInfo memberInfo, out AggregationExpression result)
        {
            result = null;

            var memberName = memberInfo.Name;

            if ((memberName == "Count" || memberName == "LongCount") && memberInfo is PropertyInfo propertyInfo)
            {
                var containerType = container.Expression.Type;
                if (containerType.Implements(typeof(ICollection)) || containerType.Implements(typeof(ICollection <>)))
                {
                    var ast        = AstExpression.Size(container.Ast);
                    var serializer = BsonSerializer.LookupSerializer(propertyInfo.PropertyType);

                    result = new AggregationExpression(expression, ast, serializer);
                    return(true);
                }
            }

            return(false);
        }