Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,10 @@ public class CoreFeatureConfiguration
/// SearchParameter cache synchronized across instances. Default is 1 minute if not specified.
/// </summary>
public int SearchParameterCacheRefreshIntervalMinutes { get; set; } = 1;

/// <summary>
/// Gets or sets the query configuration.
/// </summary>
public QueryConfiguration Query { get; set; } = new QueryConfiguration();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using Microsoft.Health.Fhir.Core.Features.Operations;

namespace Microsoft.Health.Fhir.Core.Configs
{
public class OperationsConfiguration
Expand Down
15 changes: 15 additions & 0 deletions src/Microsoft.Health.Fhir.Core/Configs/QueryConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

namespace Microsoft.Health.Fhir.Core.Configs
{
public class QueryConfiguration
{
/// <summary>
/// If Dynamic Sql Query Plan Selection is enabled.
/// </summary>
public bool DynamicSqlQueryPlanSelectionEnabled { get; set; } = false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ string ValueToString()
return $"(Field{BinaryOperator} {(ComponentIndex == null ? null : $"[{ComponentIndex}].")}{FieldName} {ValueToString()})";
}

public override string GetUniqueExpressionIdentifier()
{
return $"(Field{BinaryOperator} {(ComponentIndex == null ? null : $"[{ComponentIndex}].")}{FieldName})";
}

public override void AddValueInsensitiveHashCode(ref HashCode hashCode)
{
hashCode.Add(typeof(BinaryExpression));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ public override string ToString()
return $"({(Reversed ? "Reverse " : string.Empty)}Chain {ReferenceSearchParameter.Code}:{string.Join(", ", TargetResourceTypes)} {Expression})";
}

public override string GetUniqueExpressionIdentifier()
{
return $"({(Reversed ? "Reverse " : string.Empty)}Chain {ReferenceSearchParameter.Code}:{string.Join(", ", TargetResourceTypes)} {Expression?.GetUniqueExpressionIdentifier()})";
}

public override void AddValueInsensitiveHashCode(ref HashCode hashCode)
{
hashCode.Add(typeof(ChainedExpression));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ public override string ToString()
return $"(Compartment {CompartmentType} '{CompartmentId}')";
}

public override string GetUniqueExpressionIdentifier()
{
return $"(Compartment {CompartmentType})";
}

public override void AddValueInsensitiveHashCode(ref HashCode hashCode)
{
hashCode.Add(typeof(CompartmentSearchExpression));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using System;
using System.Collections.Generic;
using Microsoft.Health.Core.Extensions;
using Microsoft.Health.Fhir.Core.Models;

namespace Microsoft.Health.Fhir.Core.Features.Search.Expressions
Expand Down Expand Up @@ -316,11 +317,21 @@ public static NotReferencedExpression NotReferenced()
return new NotReferencedExpression();
}

public string GetHashedUniqueExpressionIdentifier()
{
return GetUniqueExpressionIdentifier()?.ComputeHash();
}

public abstract TOutput AcceptVisitor<TContext, TOutput>(IExpressionVisitor<TContext, TOutput> visitor, TContext context);

/// <inheritdoc />
public abstract override string ToString();

/// <summary>
/// Given an expression, returns its unique identifier, ignoring parameterizable values.
/// </summary>
public abstract string GetUniqueExpressionIdentifier();

/// <summary>
/// Accumulates a "value-insensitive" hash code of this instance, meaning it ignores parameterizable values.
/// For example, date=2013&amp;name=Smith and date=2014&amp;name=Trudeau would have the same hash code.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ public override string ToString()
return $"({(ComponentIndex == null ? null : $"[{ComponentIndex}].")}{FieldName} IN ({string.Join(", ", Values)}))";
}

public override string GetUniqueExpressionIdentifier()
{
return $"({(ComponentIndex == null ? null : $"[{ComponentIndex}].")}{FieldName})";
}

public override void AddValueInsensitiveHashCode(ref HashCode hashCode)
{
hashCode.Add(typeof(InExpression<T>));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ public override string ToString()
return $"({reversed}Include{iterate}{wildcard}{paramName}{targetType})";
}

public override string GetUniqueExpressionIdentifier()
{
return ToString();
}

private IReadOnlyCollection<string> GetRequiredResources()
{
if (Reversed)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ public override string ToString()
return $"(MissingField {(ComponentIndex == null ? null : $"[{ComponentIndex}].")}{FieldName})";
}

public override string GetUniqueExpressionIdentifier()
{
return ToString();
}

public override void AddValueInsensitiveHashCode(ref HashCode hashCode)
{
hashCode.Add(typeof(MissingFieldException));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ public override string ToString()
return $"({(!IsMissing ? "Not" : null)}MissingParam {Parameter.Name})";
}

public override string GetUniqueExpressionIdentifier()
{
return ToString();
}

public override void AddValueInsensitiveHashCode(ref HashCode hashCode)
{
hashCode.Add(typeof(MissingSearchParameterExpression));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ public override string ToString()
return $"({MultiaryOperation} {string.Join(' ', Expressions)})";
}

public override string GetUniqueExpressionIdentifier()
{
return $"({MultiaryOperation} {string.Join(' ', Expressions.Select(e => e.GetUniqueExpressionIdentifier()))})";
}

public override void AddValueInsensitiveHashCode(ref HashCode hashCode)
{
hashCode.Add(typeof(MultiaryExpression));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public override string ToString()
return $"(Not {Expression})";
}

public override string GetUniqueExpressionIdentifier()
{
return $"(Not {Expression?.GetUniqueExpressionIdentifier()})";
}

public override void AddValueInsensitiveHashCode(ref HashCode hashCode)
{
hashCode.Add(typeof(NotExpression));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@
// -------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EnsureThat;

namespace Microsoft.Health.Fhir.Core.Features.Search.Expressions
Expand All @@ -30,6 +26,11 @@ public override string ToString()
return "NotReferenced";
}

public override string GetUniqueExpressionIdentifier()
{
return ToString();
}

public override void AddValueInsensitiveHashCode(ref HashCode hashCode)
{
hashCode.Add(typeof(NotReferencedExpression));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@ public override string ToString()
return $"(Param {Parameter.Code} {Expression})";
}

public override string GetUniqueExpressionIdentifier()
{
// ResourceType is a special case where the expression requires the value to be included.
if (Parameter.Code == SearchParameterNames.ResourceType)
{
return $"(Param {Parameter.Code} {Expression})";
}
else
{
return $"(Param {Parameter.Code} {Expression?.GetUniqueExpressionIdentifier()})";
}
}

public override void AddValueInsensitiveHashCode(ref HashCode hashCode)
{
hashCode.Add(typeof(SearchParameterExpression));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ public override string ToString()
return $"(Sort Param: {Parameter.Code})";
}

public override string GetUniqueExpressionIdentifier()
{
return ToString();
}

public override void AddValueInsensitiveHashCode(ref HashCode hashCode)
{
hashCode.Add(typeof(SortExpression));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,19 @@ public override string ToString()
return $"(String{StringOperator}{(IgnoreCase ? "IgnoreCase" : null)} {(ComponentIndex == null ? null : $"[{ComponentIndex}].")}{FieldName} '{Value}')";
}

public override string GetUniqueExpressionIdentifier()
{
// ReferenceResourceType is a special case where the expression requires the value to be included.
if (FieldName == FieldName.ReferenceResourceType)
{
return $"(String{StringOperator}{(IgnoreCase ? "IgnoreCase" : null)} {(ComponentIndex == null ? null : $"[{ComponentIndex}].")}{FieldName} '{Value}')";
}
else
{
return $"(String{StringOperator}{(IgnoreCase ? "IgnoreCase" : null)} {(ComponentIndex == null ? null : $"[{ComponentIndex}].")}{FieldName})";
}
}

public override void AddValueInsensitiveHashCode(ref HashCode hashCode)
{
hashCode.Add(typeof(StringExpression));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ public override string ToString()
return $"(Union ({Operator}) {Expressions} {string.Join(' ', Expressions)})";
}

public override string GetUniqueExpressionIdentifier()
{
return $"(Union ({Operator}) {Expressions} {string.Join(' ', Expressions.Select(e => e.GetUniqueExpressionIdentifier()))})";
}

public override void AddValueInsensitiveHashCode(ref HashCode hashCode)
{
hashCode.Add(typeof(UnionExpression));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
<EmbeddedResource Include="Data\OperationDefinition\bulk-update.json" />
<EmbeddedResource Include="Data\OperationDefinition\bulk-delete-soft-deleted.json" />
<EmbeddedResource Include="Data\OperationDefinition\includes.json" />
<EmbeddedResource Include="Data\OperationDefinition\docref.json" />
<EmbeddedResource Include="Data\Stu3\search-parameters.json" />
<EmbeddedResource Include="Data\Stu3\unsupported-search-parameters.json" />
<EmbeddedResource Include="Data\Stu3\resourcepath-codesystem-mappings.json" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public static IFhirServerBuilder AddFhirServer(
services.AddSingleton(Options.Options.Create(fhirServerConfiguration.Security));
services.AddSingleton(Options.Options.Create(fhirServerConfiguration.Features));
services.AddSingleton(Options.Options.Create(fhirServerConfiguration.CoreFeatures));
services.AddSingleton(Options.Options.Create(fhirServerConfiguration.CoreFeatures.Query));
services.AddSingleton(Options.Options.Create(fhirServerConfiguration.Cors));
services.AddSingleton(Options.Options.Create(fhirServerConfiguration.Operations));
services.AddSingleton(Options.Options.Create(fhirServerConfiguration.Operations.Export));
Expand Down
5 changes: 4 additions & 1 deletion src/Microsoft.Health.Fhir.Shared.Web/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@
"Default": "versioned",
"ResourceTypeOverrides": null
},
"SearchParameterCacheRefreshIntervalMinutes": 1
"SearchParameterCacheRefreshIntervalMinutes": 1,
"Query": {
"DynamicSqlQueryPlanSelectionEnabled": false
}
},
"CosmosDb": {
"CollectionId": null,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using Microsoft.Health.Fhir.Core.Features.Search.Expressions;
using Xunit;

namespace Microsoft.Health.Fhir.SqlServer.UnitTests.Features.Search.Expressions
{
public sealed class ExpressionTestUtilities
{
internal static void ValidateUniqueExpressionIdentifier(Expression expression)
{
var identifier = expression.GetUniqueExpressionIdentifier();
var hash = expression.GetHashedUniqueExpressionIdentifier();
Assert.NotEqual(identifier, hash);
Assert.Equal(64, hash.Length);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ public void GivenAMultiaryExpressionWithASingleElement_WhenFlattened_RemovesTheM
{
MultiaryExpression inputExpression = Expression.And(Expression.Equals(FieldName.Number, null, 1));
Expression visitedExpression = inputExpression.AcceptVisitor(FlatteningRewriter.Instance);

Assert.Equal("(FieldEqual Number 1)", visitedExpression.ToString());

ExpressionTestUtilities.ValidateUniqueExpressionIdentifier(visitedExpression);
}

[Fact]
Expand All @@ -33,6 +36,8 @@ public void GivenTwoLayersOfAndExpressions_WhenFlattened_CombinesToOneAndExpress

Expression visitedExpression = inputExpression.AcceptVisitor(FlatteningRewriter.Instance);
Assert.Equal("(And (FieldGreaterThan Number 1) (FieldLessThan Number 5) (FieldGreaterThan Quantity 1) (FieldLessThan Quantity 5))", visitedExpression.ToString());

ExpressionTestUtilities.ValidateUniqueExpressionIdentifier(visitedExpression);
}

[Fact]
Expand All @@ -45,6 +50,8 @@ public void GivenTwoLayersOfOrExpressions_WhenFlattened_CombinesToOneOrExpressio

Expression visitedExpression = inputExpression.AcceptVisitor(FlatteningRewriter.Instance);
Assert.Equal("(Or (FieldGreaterThan Number 1) (FieldLessThan Number 5) (FieldGreaterThan Quantity 1) (FieldLessThan Quantity 5))", visitedExpression.ToString());

ExpressionTestUtilities.ValidateUniqueExpressionIdentifier(visitedExpression);
}

[Fact]
Expand All @@ -57,6 +64,8 @@ public void GivenAnOrExpressionWithAnAndChild_WhenFlattened_RemainsTheSame()

Expression visitedExpression = inputExpression.AcceptVisitor(FlatteningRewriter.Instance);
Assert.Equal("(Or (And (FieldGreaterThan Number 1) (FieldLessThan Number 5)) (And (FieldGreaterThan Quantity 1) (FieldLessThan Quantity 5)))", visitedExpression.ToString());

ExpressionTestUtilities.ValidateUniqueExpressionIdentifier(visitedExpression);
}
}
}
Loading
Loading