Skip to content

Commit

Permalink
Cosmos: Stop nesting results in extra JSON object
Browse files Browse the repository at this point in the history
Closes dotnet#25527

Reimplement via ProjectionExpression.IsValueProjection

Materializer changes.

Revert "Update dependencies from https://github.com/dotnet/runtime build 20240602.3 (dotnet#33880)"

This reverts commit c7f369c.
  • Loading branch information
roji authored and ajcvickers committed Jul 7, 2024
1 parent 09247f4 commit 93a2eae
Show file tree
Hide file tree
Showing 32 changed files with 1,339 additions and 1,265 deletions.
60 changes: 30 additions & 30 deletions eng/Version.Details.xml
Original file line number Diff line number Diff line change
@@ -1,71 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<Dependencies>
<ProductDependencies>
<Dependency Name="Microsoft.Extensions.Caching.Memory" Version="9.0.0-preview.7.24328.10">
<Dependency Name="Microsoft.Extensions.Caching.Memory" Version="9.0.0-preview.5.24275.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>a900bbf6fcf33fa2e799ed599ab86e00d6124c05</Sha>
<Sha>35e4aad602ee3c28330e94746cfd4e0d4569b66f</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.0-preview.7.24328.10">
<Dependency Name="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.0-preview.5.24275.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>a900bbf6fcf33fa2e799ed599ab86e00d6124c05</Sha>
<Sha>35e4aad602ee3c28330e94746cfd4e0d4569b66f</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.0-preview.7.24328.10">
<Dependency Name="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.0-preview.5.24275.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>a900bbf6fcf33fa2e799ed599ab86e00d6124c05</Sha>
<Sha>35e4aad602ee3c28330e94746cfd4e0d4569b66f</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.Json" Version="9.0.0-preview.7.24328.10">
<Dependency Name="Microsoft.Extensions.Configuration.Json" Version="9.0.0-preview.5.24275.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>a900bbf6fcf33fa2e799ed599ab86e00d6124c05</Sha>
<Sha>35e4aad602ee3c28330e94746cfd4e0d4569b66f</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration" Version="9.0.0-preview.7.24328.10">
<Dependency Name="Microsoft.Extensions.Configuration" Version="9.0.0-preview.5.24275.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>a900bbf6fcf33fa2e799ed599ab86e00d6124c05</Sha>
<Sha>35e4aad602ee3c28330e94746cfd4e0d4569b66f</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.DependencyInjection" Version="9.0.0-preview.7.24328.10">
<Dependency Name="Microsoft.Extensions.DependencyInjection" Version="9.0.0-preview.5.24275.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>a900bbf6fcf33fa2e799ed599ab86e00d6124c05</Sha>
<Sha>35e4aad602ee3c28330e94746cfd4e0d4569b66f</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.DependencyModel" Version="9.0.0-preview.7.24328.10">
<Dependency Name="Microsoft.Extensions.DependencyModel" Version="9.0.0-preview.5.24275.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>a900bbf6fcf33fa2e799ed599ab86e00d6124c05</Sha>
<Sha>35e4aad602ee3c28330e94746cfd4e0d4569b66f</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.HostFactoryResolver.Sources" Version="9.0.0-preview.7.24328.10">
<Dependency Name="Microsoft.Extensions.HostFactoryResolver.Sources" Version="9.0.0-preview.5.24275.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>a900bbf6fcf33fa2e799ed599ab86e00d6124c05</Sha>
<Sha>35e4aad602ee3c28330e94746cfd4e0d4569b66f</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Logging" Version="9.0.0-preview.7.24328.10">
<Dependency Name="Microsoft.Extensions.Logging" Version="9.0.0-preview.5.24275.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>a900bbf6fcf33fa2e799ed599ab86e00d6124c05</Sha>
<Sha>35e4aad602ee3c28330e94746cfd4e0d4569b66f</Sha>
</Dependency>
<Dependency Name="Microsoft.NETCore.App.Ref" Version="9.0.0-preview.7.24328.10">
<Dependency Name="Microsoft.NETCore.App.Ref" Version="9.0.0-preview.5.24275.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>a900bbf6fcf33fa2e799ed599ab86e00d6124c05</Sha>
<Sha>35e4aad602ee3c28330e94746cfd4e0d4569b66f</Sha>
</Dependency>
<!--
Win-x64 is used here because we have picked an arbitrary runtime identifier to flow the version of the latest NETCore.App runtime.
All Runtime.$rid packages should have the same version.
-->
<Dependency Name="Microsoft.NETCore.App.Runtime.win-x64" Version="9.0.0-preview.7.24328.10">
<Dependency Name="Microsoft.NETCore.App.Runtime.win-x64" Version="9.0.0-preview.5.24275.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>a900bbf6fcf33fa2e799ed599ab86e00d6124c05</Sha>
<Sha>35e4aad602ee3c28330e94746cfd4e0d4569b66f</Sha>
</Dependency>
<Dependency Name="System.Text.Json" Version="9.0.0-preview.7.24328.10">
<Dependency Name="System.Text.Json" Version="9.0.0-preview.5.24275.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>a900bbf6fcf33fa2e799ed599ab86e00d6124c05</Sha>
<Sha>35e4aad602ee3c28330e94746cfd4e0d4569b66f</Sha>
</Dependency>
</ProductDependencies>
<ToolsetDependencies>
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="9.0.0-beta.24327.1">
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="9.0.0-beta.24281.1">
<Uri>https://github.com/dotnet/arcade</Uri>
<Sha>ede13bd35571c0c8b0c01edcb057031904c5c955</Sha>
<Sha>e6b3f32f9855dccbe2447471c8f729b66f17d242</Sha>
</Dependency>
<Dependency Name="Microsoft.DotNet.Build.Tasks.Templating" Version="9.0.0-beta.24327.1">
<Dependency Name="Microsoft.DotNet.Build.Tasks.Templating" Version="9.0.0-beta.24281.1">
<Uri>https://github.com/dotnet/arcade</Uri>
<Sha>ede13bd35571c0c8b0c01edcb057031904c5c955</Sha>
<Sha>e6b3f32f9855dccbe2447471c8f729b66f17d242</Sha>
</Dependency>
<Dependency Name="Microsoft.DotNet.Helix.Sdk" Version="9.0.0-beta.24327.1">
<Dependency Name="Microsoft.DotNet.Helix.Sdk" Version="9.0.0-beta.24281.1">
<Uri>https://github.com/dotnet/arcade</Uri>
<Sha>ede13bd35571c0c8b0c01edcb057031904c5c955</Sha>
<Sha>e6b3f32f9855dccbe2447471c8f729b66f17d242</Sha>
</Dependency>
</ToolsetDependencies>
</Dependencies>
28 changes: 14 additions & 14 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup Label="Version settings">
<VersionPrefix>9.0.0</VersionPrefix>
<PreReleaseVersionLabel>preview</PreReleaseVersionLabel>
<PreReleaseVersionIteration>7</PreReleaseVersionIteration>
<PreReleaseVersionIteration>6</PreReleaseVersionIteration>
<IncludeSourceRevisionInInformationalVersion>False</IncludeSourceRevisionInInformationalVersion>
<IsServicingBuild Condition="'$(PreReleaseVersionLabel)' == 'servicing'">true</IsServicingBuild>
<!--
Expand All @@ -16,21 +16,21 @@
<UsingToolXliff>False</UsingToolXliff>
</PropertyGroup>
<PropertyGroup Label="Dependencies from dotnet/runtime">
<MicrosoftExtensionsCachingMemoryVersion>9.0.0-preview.7.24328.10</MicrosoftExtensionsCachingMemoryVersion>
<MicrosoftExtensionsConfigurationVersion>9.0.0-preview.7.24328.10</MicrosoftExtensionsConfigurationVersion>
<MicrosoftExtensionsConfigurationAbstractionsVersion>9.0.0-preview.7.24328.10</MicrosoftExtensionsConfigurationAbstractionsVersion>
<MicrosoftExtensionsConfigurationEnvironmentVariablesVersion>9.0.0-preview.7.24328.10</MicrosoftExtensionsConfigurationEnvironmentVariablesVersion>
<MicrosoftExtensionsConfigurationJsonVersion>9.0.0-preview.7.24328.10</MicrosoftExtensionsConfigurationJsonVersion>
<MicrosoftExtensionsDependencyInjectionVersion>9.0.0-preview.7.24328.10</MicrosoftExtensionsDependencyInjectionVersion>
<MicrosoftExtensionsDependencyModelVersion>9.0.0-preview.7.24328.10</MicrosoftExtensionsDependencyModelVersion>
<MicrosoftExtensionsHostFactoryResolverSourcesVersion>9.0.0-preview.7.24328.10</MicrosoftExtensionsHostFactoryResolverSourcesVersion>
<MicrosoftExtensionsLoggingVersion>9.0.0-preview.7.24328.10</MicrosoftExtensionsLoggingVersion>
<MicrosoftNETCoreAppRefVersion>9.0.0-preview.7.24328.10</MicrosoftNETCoreAppRefVersion>
<MicrosoftNETCoreAppRuntimewinx64Version>9.0.0-preview.7.24328.10</MicrosoftNETCoreAppRuntimewinx64Version>
<SystemTextJsonVersion>9.0.0-preview.7.24328.10</SystemTextJsonVersion>
<MicrosoftExtensionsCachingMemoryVersion>9.0.0-preview.5.24275.1</MicrosoftExtensionsCachingMemoryVersion>
<MicrosoftExtensionsConfigurationVersion>9.0.0-preview.5.24275.1</MicrosoftExtensionsConfigurationVersion>
<MicrosoftExtensionsConfigurationAbstractionsVersion>9.0.0-preview.5.24275.1</MicrosoftExtensionsConfigurationAbstractionsVersion>
<MicrosoftExtensionsConfigurationEnvironmentVariablesVersion>9.0.0-preview.5.24275.1</MicrosoftExtensionsConfigurationEnvironmentVariablesVersion>
<MicrosoftExtensionsConfigurationJsonVersion>9.0.0-preview.5.24275.1</MicrosoftExtensionsConfigurationJsonVersion>
<MicrosoftExtensionsDependencyInjectionVersion>9.0.0-preview.5.24275.1</MicrosoftExtensionsDependencyInjectionVersion>
<MicrosoftExtensionsDependencyModelVersion>9.0.0-preview.5.24275.1</MicrosoftExtensionsDependencyModelVersion>
<MicrosoftExtensionsHostFactoryResolverSourcesVersion>9.0.0-preview.5.24275.1</MicrosoftExtensionsHostFactoryResolverSourcesVersion>
<MicrosoftExtensionsLoggingVersion>9.0.0-preview.5.24275.1</MicrosoftExtensionsLoggingVersion>
<MicrosoftNETCoreAppRefVersion>9.0.0-preview.5.24275.1</MicrosoftNETCoreAppRefVersion>
<MicrosoftNETCoreAppRuntimewinx64Version>9.0.0-preview.5.24275.1</MicrosoftNETCoreAppRuntimewinx64Version>
<SystemTextJsonVersion>9.0.0-preview.5.24275.1</SystemTextJsonVersion>
</PropertyGroup>
<PropertyGroup Label="Dependencies from dotnet/arcade">
<MicrosoftDotNetBuildTasksTemplatingVersion>9.0.0-beta.24327.1</MicrosoftDotNetBuildTasksTemplatingVersion>
<MicrosoftDotNetBuildTasksTemplatingVersion>9.0.0-beta.24281.1</MicrosoftDotNetBuildTasksTemplatingVersion>
</PropertyGroup>
<PropertyGroup Label="Other dependencies">
<MicrosoftBuildFrameworkVersion>17.9.5</MicrosoftBuildFrameworkVersion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,6 @@ public static bool TryExtractArray(
Limit: null,
Orderings: [],
IsDistinct: false,
UsesSingleValueProjection: true,
Projection: [{ Expression: var a }]
},
}
Expand Down
42 changes: 23 additions & 19 deletions src/EFCore.Cosmos/Query/Internal/CosmosQuerySqlGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,16 +209,28 @@ protected override Expression VisitScalarSubquery(ScalarSubqueryExpression scala
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
protected override Expression VisitProjection(ProjectionExpression projectionExpression)
=> VisitProjection(projectionExpression, objectProjectionStyle: false);
{
GenerateProjection(projectionExpression, objectProjectionStyle: false);
return projectionExpression;
}

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
protected virtual Expression VisitProjection(ProjectionExpression projectionExpression, bool objectProjectionStyle)
private void GenerateProjection(ProjectionExpression projectionExpression, bool objectProjectionStyle)
{
// If the SELECT projects a single value out, we just project that with the Cosmos VALUE keyword (without VALUE,
// Cosmos projects a JSON object containing the value).
if (projectionExpression.IsValueProjection)
{
_sqlBuilder.Append("VALUE ");
Visit(projectionExpression.Expression);
return;
}

if (objectProjectionStyle)
{
_sqlBuilder.Append('"').Append(projectionExpression.Alias).Append("\" : ");
Expand All @@ -232,8 +244,6 @@ protected virtual Expression VisitProjection(ProjectionExpression projectionExpr
{
_sqlBuilder.Append(" AS " + projectionExpression.Alias);
}

return projectionExpression;
}

/// <summary>
Expand Down Expand Up @@ -279,27 +289,22 @@ protected override Expression VisitSelect(SelectExpression selectExpression)

if (selectExpression.Projection is { Count: > 0 } projection)
{
// If the SELECT projects a single value out, we just project that with the Cosmos VALUE keyword (without VALUE,
// Cosmos projects a JSON object containing the value).
// TODO: Ideally, just always use VALUE for all single-projection SELECTs - but this like requires shaper changes.
if (selectExpression.UsesSingleValueProjection && projection is [var singleProjection])
{
_sqlBuilder.Append("VALUE ");
Check.DebugAssert(
projection.Count == 1 || !projection.Any(p => p.IsValueProjection),
"Multiple projections with IsValueProjection");

Visit(singleProjection.Expression);
}
// Otherwise, we'll project a JSON object; Cosmos has two syntaxes for doing so:
// 1. Project out a JSON object as a value (SELECT VALUE { 'a': a, 'b': b }), or
// 2. Project a set of properties with optional AS+aliases (SELECT 'a' AS a, 'b' AS b)
// Both methods produce the exact same results; we usually prefer the 1st, but in some cases we use the 2nd.
else if ((projection.Count > 1
// Cosmos does not support "AS Value" projections, specifically for the alias "Value"
|| projection is [{ Alias: var alias }] && alias.Equals("value", StringComparison.OrdinalIgnoreCase))
&& projection.Any(p => !string.IsNullOrEmpty(p.Alias) && p.Alias != p.Name)
&& !projection.Any(p => p.Expression is SqlFunctionExpression)) // Aggregates are not allowed
if ((projection.Count > 1
// Cosmos does not support "AS Value" projections, specifically for the alias "Value"
|| projection is [{ Alias: { } alias }] && alias.Equals("value", StringComparison.OrdinalIgnoreCase))
&& projection.Any(p => !string.IsNullOrEmpty(p.Alias) && p.Alias != p.Name)
&& !projection.Any(p => p.Expression is SqlFunctionExpression)) // Aggregates are not allowed
{
_sqlBuilder.AppendLine("VALUE").AppendLine("{").IncrementIndent();
GenerateList(projection, e => VisitProjection(e, objectProjectionStyle: true), joinAction: sql => sql.AppendLine(","));
GenerateList(projection, e => GenerateProjection(e, objectProjectionStyle: true), joinAction: sql => sql.AppendLine(","));
_sqlBuilder.AppendLine().DecrementIndent().Append("}");
}
else
Expand Down Expand Up @@ -752,7 +757,6 @@ void VisitContainerExpression(Expression containerExpression)
Limit: null,
Orderings: [],
IsDistinct: false,
UsesSingleValueProjection: true,
Projection.Count: 1
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ public partial class CosmosShapedQueryCompilingExpressionVisitor
{
private sealed class CosmosProjectionBindingRemovingExpressionVisitor(
SelectExpression selectExpression,
ParameterExpression jObjectParameter,
ParameterExpression jTokenParameter,
bool trackQueryResults)
: CosmosProjectionBindingRemovingExpressionVisitorBase(jObjectParameter, trackQueryResults)
: CosmosProjectionBindingRemovingExpressionVisitorBase(jTokenParameter, trackQueryResults)
{
protected override ProjectionExpression GetProjection(ProjectionBindingExpression projectionBindingExpression)
=> selectExpression.Projection[GetProjectionIndex(projectionBindingExpression)];
Expand Down
Loading

0 comments on commit 93a2eae

Please sign in to comment.