Skip to content

Commit

Permalink
Annotate most of the Cosmos query pipeline for NRTs
Browse files Browse the repository at this point in the history
Excludes shaper generation for now.

Part of dotnet#26558
  • Loading branch information
roji committed Apr 21, 2024
1 parent 3163cb9 commit fa0973f
Show file tree
Hide file tree
Showing 55 changed files with 473 additions and 464 deletions.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

8 changes: 3 additions & 5 deletions src/EFCore.Cosmos/Query/Internal/CosmosRandomTranslator.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal;

/// <summary>
Expand All @@ -14,7 +12,7 @@ namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal;
public class CosmosRandomTranslator : IMethodCallTranslator
{
private static readonly MethodInfo MethodInfo = typeof(DbFunctionsExtensions).GetRuntimeMethod(
nameof(DbFunctionsExtensions.Random), [typeof(DbFunctions)]);
nameof(DbFunctionsExtensions.Random), [typeof(DbFunctions)])!;

private readonly ISqlExpressionFactory _sqlExpressionFactory;

Expand All @@ -35,8 +33,8 @@ public CosmosRandomTranslator(ISqlExpressionFactory sqlExpressionFactory)
/// 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,
public virtual SqlExpression? Translate(
SqlExpression? instance,
MethodInfo method,
IReadOnlyList<SqlExpression> arguments,
IDiagnosticsLogger<DbLoggerCategory.Query> logger)
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;

namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal;

/// <summary>
Expand Down Expand Up @@ -59,7 +61,7 @@ private Expression VisitSelect(SelectExpression selectExpression)
var fromExpression = (RootReferenceExpression)Visit(selectExpression.FromExpression);
changed |= fromExpression != selectExpression.FromExpression;

var predicate = TryCompensateForBoolWithValueConverter((SqlExpression)Visit(selectExpression.Predicate));
var predicate = TryCompensateForBoolWithValueConverter((SqlExpression?)Visit(selectExpression.Predicate));
changed |= predicate != selectExpression.Predicate;

var orderings = new List<OrderingExpression>();
Expand All @@ -70,8 +72,8 @@ private Expression VisitSelect(SelectExpression selectExpression)
orderings.Add(ordering.Update(orderingExpression));
}

var limit = (SqlExpression)Visit(selectExpression.Limit);
var offset = (SqlExpression)Visit(selectExpression.Offset);
var limit = (SqlExpression?)Visit(selectExpression.Limit);
var offset = (SqlExpression?)Visit(selectExpression.Offset);

return changed
? selectExpression.Update(projections, fromExpression, predicate, orderings, limit, offset)
Expand All @@ -87,30 +89,22 @@ private Expression VisitSqlConditional(SqlConditionalExpression sqlConditionalEx
return sqlConditionalExpression.Update(test, ifTrue, ifFalse);
}

private SqlExpression TryCompensateForBoolWithValueConverter(SqlExpression sqlExpression)
{
if (sqlExpression is KeyAccessExpression keyAccessExpression
&& keyAccessExpression.TypeMapping!.ClrType == typeof(bool)
&& keyAccessExpression.TypeMapping!.Converter != null)
[return: NotNullIfNotNull(nameof(sqlExpression))]
private SqlExpression? TryCompensateForBoolWithValueConverter(SqlExpression? sqlExpression)
=> sqlExpression switch
{
return _sqlExpressionFactory.Equal(
sqlExpression,
_sqlExpressionFactory.Constant(true, sqlExpression.TypeMapping));
}
KeyAccessExpression keyAccessExpression
when keyAccessExpression.TypeMapping!.ClrType == typeof(bool) && keyAccessExpression.TypeMapping!.Converter != null
=> _sqlExpressionFactory.Equal(sqlExpression, _sqlExpressionFactory.Constant(true, sqlExpression.TypeMapping)),

if (sqlExpression is SqlUnaryExpression sqlUnaryExpression)
{
return sqlUnaryExpression.Update(
TryCompensateForBoolWithValueConverter(sqlUnaryExpression.Operand));
}
SqlUnaryExpression sqlUnaryExpression
=> sqlUnaryExpression.Update(TryCompensateForBoolWithValueConverter(sqlUnaryExpression.Operand)),

if (sqlExpression is SqlBinaryExpression { OperatorType: ExpressionType.AndAlso or ExpressionType.OrElse } sqlBinaryExpression)
{
return sqlBinaryExpression.Update(
TryCompensateForBoolWithValueConverter(sqlBinaryExpression.Left),
TryCompensateForBoolWithValueConverter(sqlBinaryExpression.Right));
}
SqlBinaryExpression { OperatorType: ExpressionType.AndAlso or ExpressionType.OrElse } sqlBinaryExpression
=> sqlBinaryExpression.Update(
TryCompensateForBoolWithValueConverter(sqlBinaryExpression.Left),
TryCompensateForBoolWithValueConverter(sqlBinaryExpression.Right)),

return sqlExpression;
}
_ => sqlExpression
};
}
30 changes: 15 additions & 15 deletions src/EFCore.Cosmos/Query/Internal/EntityProjectionExpression.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

using Microsoft.EntityFrameworkCore.Cosmos.Internal;

namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal;
Expand Down Expand Up @@ -71,7 +69,7 @@ public override Type Type
/// 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 string Name { get; }
public virtual string? Name { get; }

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down Expand Up @@ -117,11 +115,12 @@ public virtual Expression BindProperty(IProperty property, bool clientEval)
if (!clientEval
// TODO: Remove once __jObject is translated to the access root in a better fashion and
// would not otherwise be found to be non-translatable. See issues #17670 and #14121.
// TODO: We shouldn't be returning null from here
&& property.Name != StoreKeyConvention.JObjectPropertyName
&& expression.Name.Length == 0)
&& expression.Name?.Length is null or 0)
{
// Non-persisted property can't be translated
return null;
return null!;
}

return (Expression)expression;
Expand Down Expand Up @@ -154,10 +153,11 @@ public virtual Expression BindNavigation(INavigation navigation, bool clientEval
}

if (!clientEval
&& expression.Name.Length == 0)
&& expression.Name?.Length is null or 0)
{
// Non-persisted navigation can't be translated
return null;
// TODO: We shouldn't be returning null from here
return null!;
}

return (Expression)expression;
Expand All @@ -169,11 +169,11 @@ public virtual Expression BindNavigation(INavigation navigation, bool clientEval
/// 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 Expression BindMember(
public virtual Expression? BindMember(
string name,
Type entityType,
bool clientEval,
out IPropertyBase propertyBase)
out IPropertyBase? propertyBase)
=> BindMember(MemberIdentity.Create(name), entityType, clientEval, out propertyBase);

/// <summary>
Expand All @@ -182,14 +182,14 @@ public virtual Expression BindNavigation(INavigation navigation, bool clientEval
/// 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 Expression BindMember(
public virtual Expression? BindMember(
MemberInfo memberInfo,
Type entityType,
bool clientEval,
out IPropertyBase propertyBase)
out IPropertyBase? propertyBase)
=> BindMember(MemberIdentity.Create(memberInfo), entityType, clientEval, out propertyBase);

private Expression BindMember(MemberIdentity member, Type entityClrType, bool clientEval, out IPropertyBase propertyBase)
private Expression? BindMember(MemberIdentity member, Type? entityClrType, bool clientEval, out IPropertyBase? propertyBase)
{
var entityType = EntityType;
if (entityClrType != null
Expand All @@ -199,7 +199,7 @@ private Expression BindMember(MemberIdentity member, Type entityClrType, bool cl
}

var property = member.MemberInfo == null
? entityType.FindProperty(member.Name)
? entityType.FindProperty(member.Name!)
: entityType.FindProperty(member.MemberInfo);
if (property != null)
{
Expand All @@ -208,7 +208,7 @@ private Expression BindMember(MemberIdentity member, Type entityClrType, bool cl
}

var navigation = member.MemberInfo == null
? entityType.FindNavigation(member.Name)
? entityType.FindNavigation(member.Name!)
: entityType.FindNavigation(member.MemberInfo);
if (navigation != null)
{
Expand Down Expand Up @@ -254,7 +254,7 @@ void IPrintableExpression.Print(ExpressionPrinter expressionPrinter)
/// 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 override bool Equals(object obj)
public override bool Equals(object? obj)
=> obj != null
&& (ReferenceEquals(this, obj)
|| obj is EntityProjectionExpression entityProjectionExpression
Expand Down
4 changes: 1 addition & 3 deletions src/EFCore.Cosmos/Query/Internal/FromSqlExpression.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal;

/// <summary>
Expand Down Expand Up @@ -70,7 +68,7 @@ void IPrintableExpression.Print(ExpressionPrinter expressionPrinter)
=> expressionPrinter.Append(Sql);

/// <inheritdoc />
public override bool Equals(object obj)
public override bool Equals(object? obj)
=> obj != null
&& (ReferenceEquals(this, obj)
|| obj is FromSqlExpression fromSqlExpression
Expand Down
4 changes: 1 addition & 3 deletions src/EFCore.Cosmos/Query/Internal/IAccessExpression.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal;

/// <summary>
Expand All @@ -19,5 +17,5 @@ public interface IAccessExpression
/// 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>
string Name { get; }
string? Name { get; }
}
6 changes: 3 additions & 3 deletions src/EFCore.Cosmos/Query/Internal/ISqlExpressionFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public interface ISqlExpressionFactory
/// 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>
[return: NotNullIfNotNull("sqlExpression")]
[return: NotNullIfNotNull(nameof(sqlExpression))]
SqlExpression? ApplyTypeMapping(SqlExpression? sqlExpression, CoreTypeMapping? typeMapping);

/// <summary>
Expand All @@ -28,7 +28,7 @@ public interface ISqlExpressionFactory
/// 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>
[return: NotNullIfNotNull("sqlExpression")]
[return: NotNullIfNotNull(nameof(sqlExpression))]
SqlExpression? ApplyDefaultTypeMapping(SqlExpression? sqlExpression);

/// <summary>
Expand All @@ -37,7 +37,7 @@ public interface ISqlExpressionFactory
/// 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>
SqlBinaryExpression MakeBinary(
SqlBinaryExpression? MakeBinary(
ExpressionType operatorType,
SqlExpression left,
SqlExpression right,
Expand Down
6 changes: 1 addition & 5 deletions src/EFCore.Cosmos/Query/Internal/KeyAccessExpression.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal;

/// <summary>
Expand Down Expand Up @@ -41,9 +39,7 @@ public KeyAccessExpression(IProperty property, Expression accessExpression)
/// 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>
#pragma warning disable 109
public new virtual IProperty Property { get; }
#pragma warning restore 109

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down Expand Up @@ -101,7 +97,7 @@ public override string ToString()
/// 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 override bool Equals(object obj)
public override bool Equals(object? obj)
=> obj != null
&& (ReferenceEquals(this, obj)
|| obj is KeyAccessExpression keyAccessExpression
Expand Down
11 changes: 3 additions & 8 deletions src/EFCore.Cosmos/Query/Internal/ObjectAccessExpression.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

using Microsoft.EntityFrameworkCore.Cosmos.Internal;

namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal;
Expand All @@ -23,13 +21,10 @@ public class ObjectAccessExpression : Expression, IPrintableExpression, IAccessE
/// </summary>
public ObjectAccessExpression(INavigation navigation, Expression accessExpression)
{
Name = navigation.TargetEntityType.GetContainingPropertyName();
if (Name == null)
{
throw new InvalidOperationException(
Name = navigation.TargetEntityType.GetContainingPropertyName()
?? throw new InvalidOperationException(
CosmosStrings.NavigationPropertyIsNotAnEmbeddedEntity(
navigation.DeclaringEntityType.DisplayName(), navigation.Name));
}

Navigation = navigation;
AccessExpression = accessExpression;
Expand Down Expand Up @@ -121,7 +116,7 @@ public override string ToString()
/// 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 override bool Equals(object obj)
public override bool Equals(object? obj)
=> obj != null
&& (ReferenceEquals(this, obj)
|| obj is ObjectAccessExpression objectAccessExpression
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable warnings

using Microsoft.EntityFrameworkCore.Cosmos.Internal;

namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal;
Expand All @@ -29,13 +27,10 @@ public class ObjectArrayProjectionExpression : Expression, IPrintableExpression,
var targetType = navigation.TargetEntityType;
Type = typeof(IEnumerable<>).MakeGenericType(targetType.ClrType);

Name = targetType.GetContainingPropertyName();
if (Name == null)
{
throw new InvalidOperationException(
Name = targetType.GetContainingPropertyName()
?? throw new InvalidOperationException(
CosmosStrings.NavigationPropertyIsNotAnEmbeddedEntity(
navigation.DeclaringEntityType.DisplayName(), navigation.Name));
}

Navigation = navigation;
AccessExpression = accessExpression;
Expand Down Expand Up @@ -145,7 +140,7 @@ public override string ToString()
/// 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 override bool Equals(object obj)
public override bool Equals(object? obj)
=> obj != null
&& (ReferenceEquals(this, obj)
|| obj is ObjectArrayProjectionExpression arrayProjectionExpression
Expand Down
6 changes: 2 additions & 4 deletions src/EFCore.Cosmos/Query/Internal/ProjectionExpression.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal;

/// <summary>
Expand Down Expand Up @@ -47,7 +45,7 @@ public ProjectionExpression(Expression expression, string alias)
/// 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 string Name
public virtual string? Name
=> (Expression as IAccessExpression)?.Name;

/// <summary>
Expand Down Expand Up @@ -109,7 +107,7 @@ void IPrintableExpression.Print(ExpressionPrinter expressionPrinter)
/// 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 override bool Equals(object obj)
public override bool Equals(object? obj)
=> obj != null
&& (ReferenceEquals(this, obj)
|| obj is ProjectionExpression projectionExpression
Expand Down

0 comments on commit fa0973f

Please sign in to comment.