Skip to content

Commit bf3065c

Browse files
authored
Merge pull request #195 from servicetitan/upstream/sessionTag
Session.Tag() method with scoped Tagging
2 parents 74d92fa + 61aa427 commit bf3065c

15 files changed

Lines changed: 614 additions & 82 deletions

File tree

Orm/Xtensive.Orm.Tests/Linq/TagTest.cs

Lines changed: 506 additions & 51 deletions
Large diffs are not rendered by default.

Orm/Xtensive.Orm/Orm/Domain.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public static Domain Demand()
9393
/// <summary>
9494
/// Gets the information about provider's capabilities.
9595
/// </summary>
96-
public ProviderInfo StorageProviderInfo { get { return Handlers.ProviderInfo; } }
96+
public ProviderInfo StorageProviderInfo => Handlers.ProviderInfo;
9797

9898
/// <summary>
9999
/// Gets the domain-level service container.
@@ -105,6 +105,13 @@ public static Domain Demand()
105105
/// </summary>
106106
public StorageNodeManager StorageNodeManager { get; private set; }
107107

108+
/// <summary>
109+
/// Indicated whether query tagging is enabled by domain configuration
110+
/// by <see cref="DomainConfiguration.TagsLocation"/> proprety set to something
111+
/// other than <see cref="TagsLocation.Nowhere"/>.
112+
/// </summary>
113+
public bool TagsEnabled { get; }
114+
108115
#region Private / internal members
109116

110117
internal EntityDataReader EntityDataReader { get; private set; }
@@ -428,6 +435,7 @@ internal Domain(DomainConfiguration configuration, object upgradeContextCookie,
428435
UpgradeContextCookie = upgradeContextCookie;
429436
SingleConnection = singleConnection;
430437
StorageNodeManager = new StorageNodeManager(Handlers);
438+
TagsEnabled = configuration.TagsLocation != TagsLocation.Nowhere;
431439
isDebugEventLoggingEnabled = OrmLog.IsLogged(LogLevel.Debug); // Just to cache this value
432440
}
433441

Orm/Xtensive.Orm/Orm/Internals/Prefetch/EntityGroupTask.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,11 @@ private QueryTask CreateQueryTask(List<Tuple> currentKeySet)
144144
parameterContext.SetValue(includeParameter, currentKeySet);
145145
var session = manager.Owner.Session;
146146
Provider = session.StorageNode.EntityFetchQueryCache.GetOrAdd(cacheKey, CreateRecordSet);
147+
if (session.Domain.TagsEnabled && session.Tags != null) {
148+
foreach (var tag in session.Tags) {
149+
Provider = new TagProvider(Provider, tag);
150+
}
151+
}
147152
var executableProvider = session.Compile(Provider);
148153
return new QueryTask(executableProvider, session.GetLifetimeToken(), parameterContext);
149154
}

Orm/Xtensive.Orm/Orm/Internals/Prefetch/EntitySetTask.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,11 @@ private QueryTask CreateQueryTask()
177177
var session = manager.Owner.Session;
178178
var scope = new CompiledQueryProcessingScope(null, null, parameterContext, false);
179179
QueryProvider = session.StorageNode.EntitySetFetchQueryCache.GetOrAdd(cacheKey, CreateRecordSetLoadingItems);
180+
if (session.Domain.TagsEnabled && session.Tags != null) {
181+
foreach (var tag in session.Tags) {
182+
QueryProvider = new TagProvider(QueryProvider, tag);
183+
}
184+
}
180185
ExecutableProvider executableProvider;
181186
using (scope.Enter()) {
182187
executableProvider = session.Compile(QueryProvider);

Orm/Xtensive.Orm/Orm/Linq/Materialization/ExpressionMaterializer.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,9 @@ private TranslatedQuery PrepareSubqueryParameters(SubQueryExpression subQueryExp
167167
var subqueryTupleParameter = context.GetTupleParameter(subQueryExpression.OuterParameter);
168168
var dataSource = projectionExpression.ItemProjector.DataSource;
169169

170-
var rootTags = context.GetAllTags();
170+
var rootTags = context.GetMainQueryTags();
171171
if (rootTags.Count > 0) {
172-
dataSource = dataSource.Tag($"{RootQueryTagsPrefix} {string.Join(' ', rootTags)}");
172+
dataSource = dataSource.Tag($"({RootQueryTagsPrefix} {string.Join(' ', rootTags)})");
173173
}
174174

175175
var newDataSource = ApplyParameterToTupleParameterRewriter.Rewrite(
@@ -191,7 +191,10 @@ private TranslatedQuery PrepareSubqueryParameters(SubQueryExpression subQueryExp
191191

192192
// 3. Make translation
193193
elementType = projectionExpression.ItemProjector.Item.Type;
194-
return context.Translator.Translate(projection, tupleParameters.Append(parameterOfTuple));
194+
195+
using (context.DisableSessionTags()) {
196+
return context.Translator.Translate(projection, tupleParameters.Append(parameterOfTuple));
197+
}
195198
}
196199

197200
protected override Expression VisitFieldExpression(FieldExpression expression)

Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,12 @@ public TranslatedQuery Translate()
4343
internal TranslatedQuery Translate(ProjectionExpression projection,
4444
IEnumerable<Parameter<Tuple>> tupleParameterBindings)
4545
{
46-
var newItemProjector = projection.ItemProjector.EnsureEntityIsJoined();
47-
var result = projection.Apply(newItemProjector);
46+
var result = projection;
47+
if (context.SessionTags != null)
48+
result = ApplySessionTags(result, context.SessionTags);
49+
var newItemProjector = result.ItemProjector.EnsureEntityIsJoined();
50+
result = result.Apply(newItemProjector);
51+
4852
var optimized = Optimize(result);
4953

5054
// Prepare cached query, if required
@@ -60,7 +64,7 @@ internal TranslatedQuery Translate(ProjectionExpression projection,
6064
var materializer = BuildMaterializer(prepared, tupleParameterBindings);
6165
var translatedQuery = new TranslatedQuery(
6266
compiled, materializer, prepared.ResultAccessMethod,
63-
projection.TupleParameterBindings, tupleParameterBindings);
67+
result.TupleParameterBindings, tupleParameterBindings);
6468

6569
// Providing the result to caching layer, if required
6670
if (compiledQueryScope != null && !translatedQuery.TupleParameters.Any()) {
@@ -104,6 +108,18 @@ private static ProjectionExpression PrepareCachedQuery(
104108
return origin;
105109
}
106110

111+
private static ProjectionExpression ApplySessionTags(ProjectionExpression origin, IReadOnlyList<string> tags)
112+
{
113+
var currentProjection = origin;
114+
foreach (var tag in tags) {
115+
var projector = currentProjection.ItemProjector;
116+
var newDataSource = projector.DataSource.Tag(tag);
117+
var newItemProjector = new ItemProjectorExpression(projector.Item, newDataSource, projector.Context);
118+
currentProjection = currentProjection.Apply(newItemProjector);
119+
}
120+
return currentProjection;
121+
}
122+
107123
private Materializer
108124
BuildMaterializer(ProjectionExpression projection, IEnumerable<Parameter<Tuple>> tupleParameters)
109125
{
@@ -194,7 +210,7 @@ internal Translator(TranslatorContext context, CompiledQueryProcessingScope comp
194210
{
195211
this.compiledQueryScope = compiledQueryScope;
196212
this.context = context;
197-
tagsEnabled = context.Domain.Configuration.TagsLocation != TagsLocation.Nowhere;
213+
tagsEnabled = context.Domain.TagsEnabled;
198214
}
199215
}
200216
}

Orm/Xtensive.Orm/Orm/Linq/TranslatorContext.cs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ internal sealed class TranslatorContext
5454

5555
public LinqBindingCollection Bindings { get; }
5656

57+
public IReadOnlyList<string> SessionTags { get; private set; }
58+
5759
public bool IsRoot(Expression expression)
5860
{
5961
return Query==expression;
@@ -87,12 +89,16 @@ public ApplyParameter GetApplyParameter(CompilableProvider provider)
8789
return parameter;
8890
}
8991

90-
public IReadOnlyList<string> GetAllTags()
91-
{
92-
if (Domain.Configuration.TagsLocation == TagsLocation.Nowhere)
93-
return Array.Empty<string>();
92+
public IReadOnlyList<string> GetMainQueryTags() =>
93+
Domain.TagsEnabled
94+
? applyParameters.Keys.OfType<TagProvider>().Select(p => p.Tag).ToList()
95+
: Array.Empty<string>();
9496

95-
return applyParameters.Keys.OfType<TagProvider>().Select(p => p.Tag).ToList();
97+
public IDisposable DisableSessionTags()
98+
{
99+
var originalTags = SessionTags;
100+
SessionTags = null;
101+
return new Disposable((b) => SessionTags = originalTags);
96102
}
97103

98104
public void RebindApplyParameter(CompilableProvider old, CompilableProvider @new)
@@ -142,6 +148,7 @@ public TranslatorContext(Session session, CompilerConfiguration rseCompilerConfi
142148

143149
Domain = session.Domain;
144150
RseCompilerConfiguration = rseCompilerConfiguration;
151+
SessionTags = (Domain.TagsEnabled) ? session.Tags : null;
145152

146153
// Applying query preprocessors
147154
query = Domain.Handler.QueryPreprocessors

Orm/Xtensive.Orm/Orm/Providers/CompilationService.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@ public sealed class CompilationService
2020
private readonly Func<CompilerConfiguration, IPreCompiler> preCompilerProvider;
2121
private readonly Func<CompilerConfiguration, ICompiler, IPostCompiler> postCompilerProvider;
2222

23-
public CompilerConfiguration CreateConfiguration(Session session)
24-
{
25-
return new CompilerConfiguration {StorageNode = session.StorageNode};
26-
}
23+
public CompilerConfiguration CreateConfiguration(Session session) =>
24+
new CompilerConfiguration { StorageNode = session.StorageNode, Tags = session.Tags };
2725

2826
public ExecutableProvider Compile(CompilableProvider provider, CompilerConfiguration configuration)
2927
{

Orm/Xtensive.Orm/Orm/Providers/CompilerConfiguration.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44
// Created by: Denis Krjuchkov
55
// Created: 2012.02.26
66

7+
using System.Collections.Generic;
8+
79
namespace Xtensive.Orm.Providers
810
{
911
public sealed class CompilerConfiguration
1012
{
1113
public bool PrepareRequest { get; set; }
14+
public IReadOnlyList<string> Tags { get; init; }
1215

1316
internal StorageNode StorageNode { get; set; }
1417

Orm/Xtensive.Orm/Orm/Providers/DomainHandler.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// Copyright (C) 2003-2010 Xtensive LLC.
2-
// All rights reserved.
3-
// For conditions of distribution and use, see license.
1+
// Copyright (C) 2003-2021 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
44
// Created by: Dmitri Maximov
55
// Created: 2008.05.19
66

@@ -20,6 +20,8 @@ namespace Xtensive.Orm.Providers
2020
/// </summary>
2121
public abstract class DomainHandler : DomainBoundHandler
2222
{
23+
private static readonly OrderingCorrector OrderingCorrector = new OrderingCorrector(ResolveOrderingDescriptor);
24+
2325
private Dictionary<Type, IMemberCompilerProvider> memberCompilerProviders;
2426

2527
/// <summary>
@@ -97,8 +99,8 @@ protected virtual IPreCompiler CreatePreCompiler(CompilerConfiguration configura
9799
return new CompositePreCompiler(
98100
applyCorrector,
99101
skipTakeCorrector,
100-
new RedundantColumnOptimizer(),
101-
new OrderingCorrector(ResolveOrderingDescriptor));
102+
RedundantColumnOptimizer.Instance,
103+
OrderingCorrector);
102104
}
103105

104106
/// <summary>

0 commit comments

Comments
 (0)