From 244d28123815d5818c59f9cd28b1f1da85bf01b3 Mon Sep 17 00:00:00 2001 From: tpz Date: Thu, 1 Feb 2024 17:14:07 +0100 Subject: [PATCH] feat: adapted to changes in evitaDB (histogram changes, inSet constraint change), removed client context for tracing, replaced with OpenTelemetry capabilities, updated zip library and dotnet path in github actions config --- .github/workflows/release.yml | 9 +- .../Config/EvitaClientConfiguration.cs | 21 ++- .../Converters/Models/EvitaEnumConverter.cs | 18 ++ .../Converters/Models/ResponseConverter.cs | 1 - .../Converters/Queries/QueryConverter.cs | 26 ++- EvitaDB.Client/EvitaClient.cs | 166 ++++++++---------- EvitaDB.Client/EvitaClientSession.cs | 126 +++++++------ EvitaDB.Client/EvitaDB.Client.csproj | 2 + .../Interceptors/ClientInterceptor.cs | 28 ++- .../Models/ExtraResults/IHistogram.cs | 4 +- EvitaDB.Client/Protos/GrpcEnums.proto | 11 ++ .../Protos/GrpcEvitaDataTypes.proto | 6 + .../Protos/GrpcEvitaSessionAPI.proto | 44 ++--- EvitaDB.Client/Protos/GrpcExtraResults.proto | 3 - EvitaDB.Client/Queries/IQueryConstraints.cs | 31 ++-- .../Queries/Requires/AttributeHistogram.cs | 15 +- .../Queries/Requires/HistogramBehavior.cs | 18 ++ .../Queries/Requires/PriceHistogram.cs | 6 + EvitaDB.Client/Session/IClientContext.cs | 134 -------------- EvitaDB.Client/Utils/ArrayUtils.cs | 4 +- EvitaDB.Client/Utils/OpenTelemetrySetup.cs | 36 ++++ .../evita-csharp-query-template.txt | 1 + EvitaDB.Test/DemoSetupFixture.cs | 16 +- 23 files changed, 361 insertions(+), 365 deletions(-) create mode 100644 EvitaDB.Client/Queries/Requires/HistogramBehavior.cs delete mode 100644 EvitaDB.Client/Session/IClientContext.cs create mode 100644 EvitaDB.Client/Utils/OpenTelemetrySetup.cs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 064646c..5e5c27d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,6 +33,7 @@ jobs: ref: ${{ github.head_ref }} fetch-depth: 0 + # in future updates of dotnet-version property, don't forget propagate this change into query validator publishing folder path - name: Setup dotnet uses: actions/setup-dotnet@v3 with: @@ -62,17 +63,17 @@ jobs: dotnet publish -r win-x64 -c Release -p:PublishSingleFile=true --self-contained false - name: Zip - uses: vimtor/action-zip@v1 + uses: vimtor/action-zip@v1.1 with: dest: 'Validator.zip' - files: 'EvitaDB.QueryValidator/bin/Release/net7.0/linux-x64/publish/Validator' + files: 'EvitaDB.QueryValidator/bin/Release/net8.0/linux-x64/publish/Validator' recursive: true - name: Zip - uses: vimtor/action-zip@v1 + uses: vimtor/action-zip@v1.1 with: dest: 'Validator-win.zip' - files: 'EvitaDB.QueryValidator/bin/Release/net7.0/win-x64/publish/Validator.exe' + files: 'EvitaDB.QueryValidator/bin/Release/net8.0/win-x64/publish/Validator.exe' recursive: true - name: Pack nuget diff --git a/EvitaDB.Client/Config/EvitaClientConfiguration.cs b/EvitaDB.Client/Config/EvitaClientConfiguration.cs index 55b0a60..72cf945 100644 --- a/EvitaDB.Client/Config/EvitaClientConfiguration.cs +++ b/EvitaDB.Client/Config/EvitaClientConfiguration.cs @@ -6,7 +6,8 @@ namespace EvitaDB.Client.Config; public record EvitaClientConfiguration( string ClientId, string Host, int Port, int SystemApiPort, bool UseGeneratedCertificate, bool UsingTrustedRootCaCertificate, bool MtlsEnabled, string? ServerCertificatePath, string? CertificateFileName, - string? CertificateKeyFileName, string? CertificateKeyPassword, string? CertificateFolderPath + string? CertificateKeyFileName, string? CertificateKeyPassword, string? CertificateFolderPath, string? TraceEndpointUrl, + string? TraceEndpointProtocol ) { private const int DefaultGrpcApiPort = 5556; @@ -26,6 +27,8 @@ public class Builder private string? CertificateKeyFileName { get; set; } private string? CertificateKeyPassword { get; set; } private string? CertificateFolderPath { get; set; } + private string? TraceEndpointUrl { get; set; } + private string? TraceEndpointProtocol { get; set; } public Builder() { @@ -110,6 +113,18 @@ public Builder SetCertificateFolderPath(string certificateFolderPath) CertificateFolderPath = certificateFolderPath; return this; } + + public Builder SetTraceEndpointUrl(string traceEndpointUrl) + { + TraceEndpointUrl = traceEndpointUrl; + return this; + } + + public Builder SetTraceEndpointProtocol(string traceEndpointProtocol) + { + TraceEndpointProtocol = traceEndpointProtocol; + return this; + } public EvitaClientConfiguration Build() { @@ -117,8 +132,8 @@ public EvitaClientConfiguration Build() ClientId, Host, Port, SystemApiPort, UseGeneratedCertificate, UsingTrustedRootCaCertificate, MtlsEnabled, ServerCertificatePath, CertificateFileName, CertificateKeyFileName, - CertificateKeyPassword, CertificateFolderPath + CertificateKeyPassword, CertificateFolderPath, TraceEndpointUrl, TraceEndpointProtocol ); } } -} \ No newline at end of file +} diff --git a/EvitaDB.Client/Converters/Models/EvitaEnumConverter.cs b/EvitaDB.Client/Converters/Models/EvitaEnumConverter.cs index 3fbe29a..29e5d7e 100644 --- a/EvitaDB.Client/Converters/Models/EvitaEnumConverter.cs +++ b/EvitaDB.Client/Converters/Models/EvitaEnumConverter.cs @@ -300,6 +300,15 @@ public static GrpcCardinality ToGrpcCardinality(Cardinality? cardinality) _ => throw new ArgumentOutOfRangeException(nameof(cardinality), cardinality, null) }; } + + public static HistogramBehavior ToHistogramBehavior(GrpcHistogramBehavior grpcHistogramBehavior) { + return grpcHistogramBehavior switch + { + GrpcHistogramBehavior.Standard => HistogramBehavior.Standard, + GrpcHistogramBehavior.Optimized => HistogramBehavior.Optimized, + _ => throw new EvitaInternalError("Unrecognized remote histogram behavior: " + grpcHistogramBehavior) + }; + } public static CatalogEvolutionMode ToCatalogEvolutionMode(GrpcCatalogEvolutionMode grpcEvolutionMode) { @@ -526,4 +535,13 @@ public static GrpcGlobalAttributeUniquenessType ToGrpcGlobalAttributeUniquenessT _ => throw new EvitaInternalError("Unrecognized global attribute uniqueness type: " + globalAttributeUniquenessType) }; } + + public static GrpcHistogramBehavior ToGrpcHistogramBehavior(HistogramBehavior histogramBehavior) { + return histogramBehavior switch + { + HistogramBehavior.Standard => GrpcHistogramBehavior.Standard, + HistogramBehavior.Optimized => GrpcHistogramBehavior.Optimized, + _ => throw new EvitaInternalError("Unrecognized histogram behavior: " + histogramBehavior) + }; + } } diff --git a/EvitaDB.Client/Converters/Models/ResponseConverter.cs b/EvitaDB.Client/Converters/Models/ResponseConverter.cs index a36dd7b..28bc976 100644 --- a/EvitaDB.Client/Converters/Models/ResponseConverter.cs +++ b/EvitaDB.Client/Converters/Models/ResponseConverter.cs @@ -264,7 +264,6 @@ private static IHistogram ToHistogram(GrpcHistogram grpcHistogram) private static Bucket ToBucket(GrpcHistogram.Types.GrpcBucket grpcBucket) { return new Bucket( - grpcBucket.Index, EvitaDataTypesConverter.ToDecimal(grpcBucket.Threshold), grpcBucket.Occurrences, grpcBucket.Requested diff --git a/EvitaDB.Client/Converters/Queries/QueryConverter.cs b/EvitaDB.Client/Converters/Queries/QueryConverter.cs index fdb3f4e..244a3aa 100644 --- a/EvitaDB.Client/Converters/Queries/QueryConverter.cs +++ b/EvitaDB.Client/Converters/Queries/QueryConverter.cs @@ -7,9 +7,9 @@ using EvitaDB.Client.Queries.Order; using EvitaDB.Client.Queries.Requires; -namespace EvitaDB.Client.Utils; +namespace EvitaDB.Client.Converters.Queries; -public class QueryConverter +public static class QueryConverter { public static List ConvertQueryParamsList(List queryParams) { @@ -123,6 +123,11 @@ public static object ConvertQueryParam(GrpcQueryParam queryParam) { return EvitaEnumConverter.ToStatisticsType(queryParam.StatisticsType); } + + if (queryParam.QueryParamCase == GrpcQueryParam.QueryParamOneofCase.HistogramBehavior) + { + return EvitaEnumConverter.ToHistogramBehavior(queryParam.HistogramBehavior); + } if (queryParam.QueryParamCase == GrpcQueryParam.QueryParamOneofCase.StringArrayValue) { @@ -239,6 +244,13 @@ public static object ConvertQueryParam(GrpcQueryParam queryParam) .Select(EvitaEnumConverter.ToStatisticsType) .ToArray(); } + + if (queryParam.QueryParamCase == GrpcQueryParam.QueryParamOneofCase.HistogramBehaviorTypeArrayValue) { + return queryParam.HistogramBehaviorTypeArrayValue + .Value + .Select(EvitaEnumConverter.ToHistogramBehavior) + .ToArray(); + } throw new EvitaInvalidUsageException("Unsupported Evita data type `" + queryParam + "` in gRPC API."); } @@ -357,6 +369,10 @@ public static GrpcQueryParam ConvertQueryParam(object parameter) { queryParam.StatisticsType = EvitaEnumConverter.ToGrpcStatisticsType(statisticsType); } + else if (parameter is HistogramBehavior histogramBehavior) + { + queryParam.HistogramBehavior = EvitaEnumConverter.ToGrpcHistogramBehavior(histogramBehavior); + } else if (parameter is string[] stringArrayValue) { @@ -484,6 +500,12 @@ public static GrpcQueryParam ConvertQueryParam(object parameter) queryParam.StatisticsTypeArrayValue = new GrpcStatisticsTypeArray {Value = {statisticsTypeArray.Select(EvitaEnumConverter.ToGrpcStatisticsType)}}; } + else if (parameter is HistogramBehavior[] histogramBehaviorArray) + { + queryParam.HistogramBehaviorTypeArrayValue = new GrpcHistogramBehaviorTypeArray() + {Value = {histogramBehaviorArray.Select(EvitaEnumConverter.ToGrpcHistogramBehavior)}}; + } + else { throw new EvitaInvalidUsageException("Unsupported Evita data type `" + parameter.GetType().Name + "` in gRPC API."); diff --git a/EvitaDB.Client/EvitaClient.cs b/EvitaDB.Client/EvitaClient.cs index 2788bd9..b32929e 100644 --- a/EvitaDB.Client/EvitaClient.cs +++ b/EvitaDB.Client/EvitaClient.cs @@ -22,6 +22,7 @@ using Google.Protobuf.WellKnownTypes; using Grpc.Core; using Enum = System.Enum; +using StatusCode = Grpc.Core.StatusCode; [assembly: InternalsVisibleTo("EvitaDB.Test")] @@ -38,7 +39,7 @@ namespace EvitaDB.Client; /// properties nor data corruption guarantees. Evita "index" must be treated as something that could be dropped any time and /// built up from scratch easily again. /// -public partial class EvitaClient : IClientContext, IDisposable +public partial class EvitaClient : IDisposable { private static readonly ISchemaMutationConverter CatalogSchemaMutationConverter = new DelegatingTopLevelCatalogSchemaMutationConverter(); @@ -52,10 +53,13 @@ private static readonly ISchemaMutationConverter _entitySchemaCache = new(); private readonly Action? _terminationCallback; + + private OpenTelemetrySetup? _openTelemetrySetup; public EvitaClientConfiguration Configuration { get; } private static readonly Regex ErrorMessagePattern = MyRegex(); + private EvitaClient(EvitaClientConfiguration configuration, ClientCertificateManager certificateManager) { Configuration = configuration; @@ -63,11 +67,17 @@ private EvitaClient(EvitaClientConfiguration configuration, ClientCertificateMan Configuration.Host, Configuration.Port, certificateManager.BuildHttpClientHandler(), - new ClientInterceptor(this) + new ClientInterceptor(configuration) ); _channelPool = new ChannelPool(channelBuilder, 10); _cdcChannel = channelBuilder.Build(); + string? traceEndpointUrl = configuration.TraceEndpointUrl; + if (traceEndpointUrl is not null) + { + _openTelemetrySetup = new OpenTelemetrySetup(configuration.TraceEndpointUrl!, configuration.TraceEndpointProtocol); + } + void TerminationCallback() { try @@ -84,6 +94,11 @@ void TerminationCallback() _terminationCallback = TerminationCallback; } + /// + /// Initialize a new instance of with the specified configuration. + /// + /// configuration to be applied + /// newly created EvitaClient public static async Task Create(EvitaClientConfiguration configuration) { ClientCertificateManager certificateManager = await new ClientCertificateManager.Builder() @@ -168,7 +183,7 @@ public EvitaClientSession CreateReadWriteSession(string catalogName) public void TerminateSession(EvitaClientSession session) { AssertActive(); - (this as IClientContext).ExecuteWithClientId(Configuration.ClientId, Close); + session.Close(); } /// @@ -193,17 +208,13 @@ public ISet GetCatalogNames() public ICatalogSchemaBuilder DefineCatalog(string catalogName) { AssertActive(); - - IClientContext context = this; - return context.ExecuteWithClientId(Configuration.ClientId, () => + + if (!GetCatalogNames().Contains(catalogName)) { - if (!GetCatalogNames().Contains(catalogName)) - { - Update(new CreateCatalogSchemaMutation(catalogName)); - } + Update(new CreateCatalogSchemaMutation(catalogName)); + } - return QueryCatalog(catalogName, x => x.GetCatalogSchema(this)).OpenForWrite(); - }); + return QueryCatalog(catalogName, x => x.GetCatalogSchema(this)).OpenForWrite(); } /// @@ -221,8 +232,7 @@ public void RenameCatalog(string catalogName, string newCatalogName) AssertActive(); GrpcRenameCatalogRequest request = new GrpcRenameCatalogRequest { - CatalogName = catalogName, - NewCatalogName = newCatalogName + CatalogName = catalogName, NewCatalogName = newCatalogName }; GrpcRenameCatalogResponse response = ExecuteWithBlockingEvitaService(evitaService => evitaService.RenameCatalog(request)); @@ -269,10 +279,7 @@ public bool DeleteCatalogIfExists(string catalogName) { AssertActive(); - GrpcDeleteCatalogIfExistsRequest request = new GrpcDeleteCatalogIfExistsRequest - { - CatalogName = catalogName - }; + GrpcDeleteCatalogIfExistsRequest request = new GrpcDeleteCatalogIfExistsRequest { CatalogName = catalogName }; GrpcDeleteCatalogIfExistsResponse grpcResponse = ExecuteWithBlockingEvitaService(evitaService => evitaService.DeleteCatalogIfExists(request)); bool success = grpcResponse.Success; @@ -298,7 +305,7 @@ public void Update(params ITopLevelCatalogSchemaMutation[] catalogMutations) .Select(CatalogSchemaMutationConverter.Convert) .ToList(); - GrpcUpdateEvitaRequest request = new GrpcUpdateEvitaRequest {SchemaMutations = {grpcSchemaMutations}}; + GrpcUpdateEvitaRequest request = new GrpcUpdateEvitaRequest { SchemaMutations = { grpcSchemaMutations } }; ExecuteWithBlockingEvitaService(evitaService => evitaService.Update(request)); } @@ -319,8 +326,7 @@ public T QueryCatalog(string catalogName, Func queryLo EvitaClientSession session = CreateSession(new SessionTraits(catalogName, sessionFlags)); try { - IClientContext context = session; - return context.ExecuteWithClientId(Configuration.ClientId, () => queryLogic.Invoke(session)); + return queryLogic.Invoke(session); } finally { @@ -345,14 +351,12 @@ public void QueryCatalog(string catalogName, Action queryLog EvitaClientSession session = CreateSession(new SessionTraits(catalogName, sessionFlags)); try { - IClientContext context = session; - context.ExecuteWithClientId(Configuration.ClientId, () => queryLogic.Invoke(session)); + queryLogic.Invoke(session); } finally { session.Close(); } - } /// @@ -373,7 +377,7 @@ public T UpdateCatalog(string catalogName, Func update SessionTraits traits = new SessionTraits( catalogName, flags == null - ? new[] {SessionFlags.ReadWrite} + ? new[] { SessionFlags.ReadWrite } : flags.Contains(SessionFlags.ReadWrite) ? flags : flags.Append(SessionFlags.ReadWrite).ToArray() @@ -381,8 +385,7 @@ public T UpdateCatalog(string catalogName, Func update EvitaClientSession session = CreateSession(traits); try { - IClientContext context = session; - return context.ExecuteWithClientId(Configuration.ClientId, () => session.Execute(updater)); + return session.Execute(updater); } finally { @@ -408,8 +411,7 @@ public void UpdateCatalog(string catalogName, Action updater catalogName, evitaSession => { - IClientContext context = evitaSession; - context.ExecuteWithClientId(Configuration.ClientId, () => updater.Invoke(evitaSession)); + updater.Invoke(evitaSession); return 0; }, flags @@ -471,67 +473,59 @@ private T ExecuteWithStreamingEvitaService(Func(IChannelSupplier channelSupplier, Func stubBuilder, Func logic) { - IClientContext context = this; - return context.ExecuteWithClientAndRequestId( - Configuration.ClientId, - Guid.NewGuid().ToString(), - () => + ChannelInvoker channel = channelSupplier.GetChannel(); + try + { + return logic.Invoke(stubBuilder.Invoke(channel)); + } + catch (RpcException rpcException) + { + StatusCode statusCode = rpcException.StatusCode; + string description = rpcException.Status.Detail; + Match expectedFormat = ErrorMessagePattern.Match(description); + if (statusCode == StatusCode.InvalidArgument) { - ChannelInvoker channel = channelSupplier.GetChannel(); - try - { - return logic.Invoke(stubBuilder.Invoke(channel)); - } - catch (RpcException rpcException) - { - StatusCode statusCode = rpcException.StatusCode; - string description = rpcException.Status.Detail; - Match expectedFormat = ErrorMessagePattern.Match(description); - if (statusCode == StatusCode.InvalidArgument) - { - if (expectedFormat.Success) - { - throw EvitaInvalidUsageException.CreateExceptionWithErrorCode( - expectedFormat.Groups[2].ToString(), expectedFormat.Groups[1].ToString() - ); - } - - throw new EvitaInvalidUsageException(description); - } - else - { - if (expectedFormat.Success) - { - throw EvitaInternalError.CreateExceptionWithErrorCode( - expectedFormat.Groups[2].ToString(), expectedFormat.Groups[1].ToString() - ); - } - - throw new EvitaInternalError(description); - } - } - catch (EvitaInvalidUsageException) - { - throw; - } - catch (EvitaInternalError) + if (expectedFormat.Success) { - throw; - } - catch (Exception e) - { - Trace.TraceError($"Unexpected internal Evita error occurred: {e.Message}", e); - throw new EvitaInternalError( - "Unexpected internal Evita error occurred: " + e.Message, - "Unexpected internal Evita error occurred.", e + throw EvitaInvalidUsageException.CreateExceptionWithErrorCode( + expectedFormat.Groups[2].ToString(), expectedFormat.Groups[1].ToString() ); } - finally + + throw new EvitaInvalidUsageException(description); + } + else + { + if (expectedFormat.Success) { - channelSupplier.ReleaseChannel(); + throw EvitaInternalError.CreateExceptionWithErrorCode( + expectedFormat.Groups[2].ToString(), expectedFormat.Groups[1].ToString() + ); } + + throw new EvitaInternalError(description); } - ); + } + catch (EvitaInvalidUsageException) + { + throw; + } + catch (EvitaInternalError) + { + throw; + } + catch (Exception e) + { + Trace.TraceError($"Unexpected internal Evita error occurred: {e.Message}", e); + throw new EvitaInternalError( + "Unexpected internal Evita error occurred: " + e.Message, + "Unexpected internal Evita error occurred.", e + ); + } + finally + { + channelSupplier.ReleaseChannel(); + } } /// @@ -546,11 +540,7 @@ private T ExecuteWithEvitaService(IChannelSupplier channelSupplier, Func< public EvitaClientSession CreateSession(SessionTraits traits) { AssertActive(); - GrpcEvitaSessionRequest grpcRequest = new() - { - CatalogName = traits.CatalogName, - DryRun = traits.IsDryRun(), - }; + GrpcEvitaSessionRequest grpcRequest = new() { CatalogName = traits.CatalogName, DryRun = traits.IsDryRun(), }; GrpcEvitaSessionResponse? grpcResponse = traits.IsReadWrite() ? ExecuteWithBlockingEvitaService(evitaServiceClient => evitaServiceClient.CreateReadWriteSession(grpcRequest)) diff --git a/EvitaDB.Client/EvitaClientSession.cs b/EvitaDB.Client/EvitaClientSession.cs index 46028df..d9f2fb5 100644 --- a/EvitaDB.Client/EvitaClientSession.cs +++ b/EvitaDB.Client/EvitaClientSession.cs @@ -5,7 +5,7 @@ using EvitaDB.Client.Converters.Models.Schema; using EvitaDB.Client.Converters.Models.Schema.Mutations; using EvitaDB.Client.Converters.Models.Schema.Mutations.Catalogs; -using EvitaDB.Client.DataTypes; +using EvitaDB.Client.Converters.Queries; using EvitaDB.Client.Exceptions; using EvitaDB.Client.Interceptors; using EvitaDB.Client.Models; @@ -26,6 +26,7 @@ using Grpc.Core; using static EvitaDB.Client.Queries.Visitor.PrettyPrintingVisitor; using static EvitaDB.Client.Queries.IQueryConstraints; +using StatusCode = Grpc.Core.StatusCode; namespace EvitaDB.Client; @@ -42,7 +43,7 @@ namespace EvitaDB.Client; /// Don't forget to when your work with Evita is finished. /// EvitaSession contract is NOT thread safe. /// -public partial class EvitaClientSession : IClientContext, IDisposable +public partial class EvitaClientSession : IDisposable { private static readonly ISchemaMutationConverter CatalogSchemaMutationConverter = new DelegatingLocalCatalogSchemaMutationConverter(); @@ -127,79 +128,73 @@ public IEntitySchemaBuilder DefineEntitySchema(string entityType) private T ExecuteWithEvitaSessionService( Func evitaSessionServiceClient) { - IClientContext clientContext = this; - return clientContext.ExecuteWithClientId( - _clientId, - () => + var channel = _channelPool.GetChannel(); + try + { + SessionIdHolder.SetSessionId(CatalogName, SessionId.ToString()); + return evitaSessionServiceClient.Invoke( + new EvitaSessionService.EvitaSessionServiceClient(channel.Invoker)); + } + catch (RpcException rpcException) + { + var statusCode = rpcException.StatusCode; + var description = rpcException.Status.Detail; + if (statusCode == StatusCode.Unauthenticated) { - var channel = _channelPool.GetChannel(); - try - { - SessionIdHolder.SetSessionId(CatalogName, SessionId.ToString()); - return evitaSessionServiceClient.Invoke( - new EvitaSessionService.EvitaSessionServiceClient(channel.Invoker)); - } - catch (RpcException rpcException) - { - var statusCode = rpcException.StatusCode; - var description = rpcException.Status.Detail; - if (statusCode == StatusCode.Unauthenticated) - { - // close session and rethrow - CloseInternally(); - throw new InstanceTerminatedException("session"); - } - else if (statusCode == StatusCode.InvalidArgument) - { - var expectedFormat = ErrorMessagePattern.Match(description); - if (expectedFormat.Success) - { - throw EvitaInvalidUsageException.CreateExceptionWithErrorCode( - expectedFormat.Groups[2].ToString(), expectedFormat.Groups[1].ToString() - ); - } - else - { - throw new EvitaInvalidUsageException(description); - } - } - else - { - var expectedFormat = ErrorMessagePattern.Match(description); - if (expectedFormat.Success) - { - throw EvitaInternalError.CreateExceptionWithErrorCode( - expectedFormat.Groups[2].ToString(), expectedFormat.Groups[1].ToString() - ); - } - else - { - throw new EvitaInternalError(description); - } - } - } - catch (EvitaInvalidUsageException) + // close session and rethrow + CloseInternally(); + throw new InstanceTerminatedException("session"); + } + else if (statusCode == StatusCode.InvalidArgument) + { + var expectedFormat = ErrorMessagePattern.Match(description); + if (expectedFormat.Success) { - throw; + throw EvitaInvalidUsageException.CreateExceptionWithErrorCode( + expectedFormat.Groups[2].ToString(), expectedFormat.Groups[1].ToString() + ); } - catch (EvitaInternalError) + else { - throw; + throw new EvitaInvalidUsageException(description); } - catch (Exception e) + } + else + { + var expectedFormat = ErrorMessagePattern.Match(description); + if (expectedFormat.Success) { - throw new EvitaInternalError( - "Unexpected internal Evita error occurred: " + e.Message, - "Unexpected internal Evita error occurred.", - e + throw EvitaInternalError.CreateExceptionWithErrorCode( + expectedFormat.Groups[2].ToString(), expectedFormat.Groups[1].ToString() ); } - finally + else { - _channelPool.ReleaseChannel(channel); - SessionIdHolder.Reset(); + throw new EvitaInternalError(description); } - }); + } + } + catch (EvitaInvalidUsageException) + { + throw; + } + catch (EvitaInternalError) + { + throw; + } + catch (Exception e) + { + throw new EvitaInternalError( + "Unexpected internal Evita error occurred: " + e.Message, + "Unexpected internal Evita error occurred.", + e + ); + } + finally + { + _channelPool.ReleaseChannel(channel); + SessionIdHolder.Reset(); + } } /// @@ -339,6 +334,7 @@ public IList QueryList(Query query) where TS : IEntityClassifier Query = stringWithParameters.Query, PositionalQueryParams = { stringWithParameters.Parameters.Select(QueryConverter.ConvertQueryParam) } }; + var grpcResponse = ExecuteWithEvitaSessionService(session => session.QueryList(request)); if (typeof(IEntityReference).IsAssignableFrom(typeof(TS))) diff --git a/EvitaDB.Client/EvitaDB.Client.csproj b/EvitaDB.Client/EvitaDB.Client.csproj index 152a741..3b33819 100644 --- a/EvitaDB.Client/EvitaDB.Client.csproj +++ b/EvitaDB.Client/EvitaDB.Client.csproj @@ -34,6 +34,8 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/EvitaDB.Client/Interceptors/ClientInterceptor.cs b/EvitaDB.Client/Interceptors/ClientInterceptor.cs index fdc09bb..f5fb71e 100644 --- a/EvitaDB.Client/Interceptors/ClientInterceptor.cs +++ b/EvitaDB.Client/Interceptors/ClientInterceptor.cs @@ -1,4 +1,4 @@ -using EvitaDB.Client.Session; +using EvitaDB.Client.Config; using Grpc.Core; using Grpc.Core.Interceptors; @@ -13,18 +13,17 @@ public class ClientInterceptor : Interceptor private const string SessionIdHeader = "sessionId"; private const string CatalogNameHeader = "catalogName"; private const string ClientIdHeader = "clientId"; - private const string RequestIdHeader = "requestId"; - private readonly IClientContext? _clientContext; + private readonly EvitaClientConfiguration? _configuration; - public ClientInterceptor(IClientContext clientContext) + public ClientInterceptor(EvitaClientConfiguration configuration) { - _clientContext = clientContext; + _configuration = configuration; } public ClientInterceptor() { - _clientContext = null; + _configuration = null; } /// @@ -37,17 +36,10 @@ public override TResponse BlockingUnaryCall(TRequest reques BlockingUnaryCallContinuation continuation) { Metadata metadata = new Metadata(); - if (_clientContext != null) { - string? clientId = _clientContext.GetClientId(); - if (clientId is not null) - { - metadata.Add(ClientIdHeader, clientId); - } - string? requestId = _clientContext.GetRequestId(); - if (requestId is not null) - { - metadata.Add(RequestIdHeader, requestId); - } + if (_configuration != null) + { + string clientId = _configuration.ClientId; + metadata.Add(ClientIdHeader, clientId); } var sessionId = SessionIdHolder.GetSessionId(); if (sessionId != null) @@ -120,4 +112,4 @@ public static void Reset() /// Name of a catalog. /// SessionID that is used internally in evitaDB to perform client's calls. private record SessionDescriptor(string CatalogName, string SessionId); -} \ No newline at end of file +} diff --git a/EvitaDB.Client/Models/ExtraResults/IHistogram.cs b/EvitaDB.Client/Models/ExtraResults/IHistogram.cs index 04f0e4c..3d476d8 100644 --- a/EvitaDB.Client/Models/ExtraResults/IHistogram.cs +++ b/EvitaDB.Client/Models/ExtraResults/IHistogram.cs @@ -13,15 +13,13 @@ public interface IHistogram public record Bucket { - public int Index { get; init; } [JsonProperty(DefaultValueHandling = DefaultValueHandling.Include)] public decimal Threshold { get; init; } public int Occurrences { get; init; } public bool Requested { get; init; } - public Bucket(int index, decimal threshold, int occurrences, bool requested) + public Bucket(decimal threshold, int occurrences, bool requested) { - Index = index; Threshold = threshold; Occurrences = occurrences; Requested = requested; diff --git a/EvitaDB.Client/Protos/GrpcEnums.proto b/EvitaDB.Client/Protos/GrpcEnums.proto index b14e14f..e76ef0a 100644 --- a/EvitaDB.Client/Protos/GrpcEnums.proto +++ b/EvitaDB.Client/Protos/GrpcEnums.proto @@ -128,6 +128,17 @@ enum GrpcStatisticsType { QUERIED_ENTITY_COUNT = 1; } +// The enum specifies whether the HistogramBehavior should produce histogram with exactly requested bucket counts +// or optimized one, which may have less buckets than requested, but is more compact +enum GrpcHistogramBehavior { + // Histogram always contains the number of buckets you asked for. This is the default behaviour. + STANDARD = 0; + // Histogram will never contain more buckets than you asked for, but may contain less when the data is scarce and + // there would be big gaps (empty buckets) between buckets. This leads to more compact histograms, which provide + // better user experience. + OPTIMIZED = 1; +} + // This enum controls how prices that share same `inner entity id` will behave during filtering and sorting. enum GrpcPriceInnerRecordHandling { // No special strategy set. Inner record id is not taken into account at all. diff --git a/EvitaDB.Client/Protos/GrpcEvitaDataTypes.proto b/EvitaDB.Client/Protos/GrpcEvitaDataTypes.proto index 528d7a3..6d86e0c 100644 --- a/EvitaDB.Client/Protos/GrpcEvitaDataTypes.proto +++ b/EvitaDB.Client/Protos/GrpcEvitaDataTypes.proto @@ -221,6 +221,12 @@ message GrpcStatisticsTypeArray { repeated GrpcStatisticsType value = 1; } +// Wrapper for representing an array of HistogramBehavior enums. +message GrpcHistogramBehaviorTypeArray { + // Value that supports storing a HistogramBehavior array. + repeated GrpcHistogramBehavior value = 1; +} + // Structure that holds one of the supported data type values, its type and version of stored value. message GrpcEvitaValue { // The stored value. May by only one of the following at the time. diff --git a/EvitaDB.Client/Protos/GrpcEvitaSessionAPI.proto b/EvitaDB.Client/Protos/GrpcEvitaSessionAPI.proto index f602c31..e07b80e 100644 --- a/EvitaDB.Client/Protos/GrpcEvitaSessionAPI.proto +++ b/EvitaDB.Client/Protos/GrpcEvitaSessionAPI.proto @@ -390,46 +390,50 @@ message GrpcQueryParam { GrpcStatisticsBase statisticsBase = 19; // The statistics type enum value. GrpcStatisticsType statisticsType = 20; + // The histogram behavior enum value. + GrpcHistogramBehavior histogramBehavior = 21; // The string array value. - GrpcStringArray stringArrayValue = 21; + GrpcStringArray stringArrayValue = 101; // The integer array value. - GrpcIntegerArray integerArrayValue = 22; + GrpcIntegerArray integerArrayValue = 102; // The long array value. - GrpcLongArray longArrayValue = 23; + GrpcLongArray longArrayValue = 103; // The boolean array value. - GrpcBooleanArray booleanArrayValue = 24; + GrpcBooleanArray booleanArrayValue = 104; // The big decimal array value. - GrpcBigDecimalArray bigDecimalArrayValue = 25; + GrpcBigDecimalArray bigDecimalArrayValue = 105; // The date time range array value. - GrpcDateTimeRangeArray dateTimeRangeArrayValue = 26; + GrpcDateTimeRangeArray dateTimeRangeArrayValue = 106; // The integer number range array value. - GrpcIntegerNumberRangeArray integerNumberRangeArrayValue = 27; + GrpcIntegerNumberRangeArray integerNumberRangeArrayValue = 107; // The long number range array value. - GrpcLongNumberRangeArray longNumberRangeArrayValue = 28; + GrpcLongNumberRangeArray longNumberRangeArrayValue = 108; // The big decimal number range array value. - GrpcBigDecimalNumberRangeArray bigDecimalNumberRangeArrayValue = 29; + GrpcBigDecimalNumberRangeArray bigDecimalNumberRangeArrayValue = 109; // The offset date time array value. - GrpcOffsetDateTimeArray offsetDateTimeArrayValue = 30; + GrpcOffsetDateTimeArray offsetDateTimeArrayValue = 110; // The locale array value. - GrpcLocaleArray localeArrayValue = 31; + GrpcLocaleArray localeArrayValue = 111; // The currency array value. - GrpcCurrencyArray currencyArrayValue = 32; + GrpcCurrencyArray currencyArrayValue = 112; // The facet statistics depth array value. - GrpcFacetStatisticsDepthArray facetStatisticsDepthArrayValue = 33; + GrpcFacetStatisticsDepthArray facetStatisticsDepthArrayValue = 113; // The query price mode array value. - GrpcQueryPriceModeArray queryPriceModelArrayValue = 34; + GrpcQueryPriceModeArray queryPriceModelArrayValue = 114; // The price content mode array value. - GrpcPriceContentModeArray priceContentModeArrayValue = 35; + GrpcPriceContentModeArray priceContentModeArrayValue = 115; // The attribute special value array value. - GrpcAttributeSpecialValueArray attributeSpecialArrayValue = 36; + GrpcAttributeSpecialValueArray attributeSpecialArrayValue = 116; // The order direction array value. - GrpcOrderDirectionArray orderDirectionArrayValue = 37; + GrpcOrderDirectionArray orderDirectionArrayValue = 117; // The empty hierarchical entity behaviour array value. - GrpcEmptyHierarchicalEntityBehaviourArray emptyHierarchicalEntityBehaviourArrayValue = 38; - GrpcStatisticsBaseArray statisticsBaseArrayValue = 39; + GrpcEmptyHierarchicalEntityBehaviourArray emptyHierarchicalEntityBehaviourArrayValue = 118; + GrpcStatisticsBaseArray statisticsBaseArrayValue = 119; // The statistics type array value. - GrpcStatisticsTypeArray statisticsTypeArrayValue = 40; + GrpcStatisticsTypeArray statisticsTypeArrayValue = 120; + // The histogram behavior enum value. + GrpcHistogramBehaviorTypeArray histogramBehaviorTypeArrayValue = 121; } } diff --git a/EvitaDB.Client/Protos/GrpcExtraResults.proto b/EvitaDB.Client/Protos/GrpcExtraResults.proto index 9018638..2441642 100644 --- a/EvitaDB.Client/Protos/GrpcExtraResults.proto +++ b/EvitaDB.Client/Protos/GrpcExtraResults.proto @@ -32,9 +32,6 @@ message GrpcHistogram { int32 overallCount = 3; // Data object that carries out threshold in histogram (or bucket if you will) along with number of occurrences in it. message GrpcBucket { - // Contains index (starting with zero) of the bucket in the histogram. First bucket / column of the histogram - // will have index zero, second bucket / column one and so forth. - int32 index = 1; // Contains threshold (left bound - inclusive) of the bucket. GrpcBigDecimal threshold = 2; // Contains number of entity occurrences in this bucket - e.g. number of entities that has monitored property value diff --git a/EvitaDB.Client/Queries/IQueryConstraints.cs b/EvitaDB.Client/Queries/IQueryConstraints.cs index d98c428..9eb62f5 100644 --- a/EvitaDB.Client/Queries/IQueryConstraints.cs +++ b/EvitaDB.Client/Queries/IQueryConstraints.cs @@ -187,25 +187,31 @@ dateTimeOffsetValue is null static AttributeInRange AttributeInRangeNow(string attributeName) => new(attributeName); /// - static AttributeInSet? AttributeInSet(string attributeName, params T[]? set) + static AttributeInSet? AttributeInSet(string? attributeName, params T?[]? set) { + if (attributeName is null) + { + return null; + } if (set is null) { return null; } - List args = set.Where(x => x is not null).ToList(); - if (args.Count == 0) + T?[] nonNullArray = set.Where(x => x is not null).ToArray(); + if (ArrayUtils.IsEmpty(nonNullArray)) { return null; } + List args = set.Where(x => x is not null).ToList(); + if (args.Count == set.Length) { return new AttributeInSet(attributeName, set); } - T[] limitedSet = (T[]) Array.CreateInstance(set.GetType().GetElementType()!, args.Count); + T?[] limitedSet = (T[]) Array.CreateInstance(set.GetType().GetElementType()!, args.Count); for (int i = 0; i < args.Count; i++) { limitedSet[i] = args[i]; @@ -215,12 +221,10 @@ dateTimeOffsetValue is null } /// - static AttributeEquals AttributeEqualsFalse(string attributeName) => - new AttributeEquals(attributeName, false); + static AttributeEquals AttributeEqualsFalse(string attributeName) => new(attributeName, false); /// - static AttributeEquals AttributeEqualsTrue(string attributeName) => - new AttributeEquals(attributeName, true); + static AttributeEquals AttributeEqualsTrue(string attributeName) => new(attributeName, true); /// static AttributeIs? AttributeIs(string attributeName, AttributeSpecialValue? specialValue) => @@ -246,8 +250,7 @@ static AttributeEquals AttributeEqualsTrue(string attributeName) => /// static FacetHaving? FacetHaving(string referenceName, params IFilterConstraint?[]? constraints) => ArrayUtils.IsEmpty(constraints) ? null : new FacetHaving(referenceName, constraints!); - - + /// static EntityPrimaryKeyInSet? EntityPrimaryKeyInSet(params int[]? primaryKeys) => primaryKeys == null ? null : new EntityPrimaryKeyInSet(primaryKeys); @@ -317,9 +320,17 @@ static AttributeNatural AttributeNatural(string attributeName, OrderDirection or /// static AttributeHistogram? AttributeHistogram(int requestedBucketCount, params string[]? attributeNames) => ArrayUtils.IsEmpty(attributeNames) ? null : new AttributeHistogram(requestedBucketCount, attributeNames!); + + /// + static AttributeHistogram? AttributeHistogram(int requestedBucketCount, HistogramBehavior? behavior, params string[]? attributeNames) => + ArrayUtils.IsEmpty(attributeNames) ? null : new AttributeHistogram(requestedBucketCount, behavior, attributeNames!); /// static PriceHistogram PriceHistogram(int requestedBucketCount) => new(requestedBucketCount); + + /// + static PriceHistogram PriceHistogram(int requestedBucketCount, HistogramBehavior? behavior) + => new(requestedBucketCount, behavior); /// static FacetGroupsConjunction? FacetGroupsConjunction(string? referenceName, FilterBy? filterBy = null) => diff --git a/EvitaDB.Client/Queries/Requires/AttributeHistogram.cs b/EvitaDB.Client/Queries/Requires/AttributeHistogram.cs index f1d4059..7bb9c0c 100644 --- a/EvitaDB.Client/Queries/Requires/AttributeHistogram.cs +++ b/EvitaDB.Client/Queries/Requires/AttributeHistogram.cs @@ -19,13 +19,18 @@ private AttributeHistogram(params object[] arguments) : base(arguments) { } - public AttributeHistogram(int requestedBucketCount, params string[] attributeNames) : base(new object[]{requestedBucketCount}.Concat(attributeNames).ToArray()) + public AttributeHistogram(int requestedBucketCount, HistogramBehavior? behavior, params string[] attributeNames) + : base(new object[]{requestedBucketCount,behavior ?? HistogramBehavior.Standard}.Concat(attributeNames).ToArray()) { } - public int RequestedBucketCount => (int) Arguments[0]!; - - public string[] AttributeNames => Arguments.Skip(1).Select(obj => (string) obj!).ToArray(); + public AttributeHistogram(int requestedBucketCount, params string[] attributeNames) + : base(new object[]{requestedBucketCount, HistogramBehavior.Standard}.Concat(attributeNames).ToArray()) + { + } - public new bool Applicable => IsArgumentsNonNull() && Arguments.Length > 1; + public int RequestedBucketCount => (int) Arguments[0]!; + public HistogramBehavior Behavior => (HistogramBehavior) Arguments[1]!; + public string[] AttributeNames => Arguments.Skip(2).Select(obj => (string) obj!).ToArray(); + public new bool Applicable => IsArgumentsNonNull() && Arguments.Length > 2; } diff --git a/EvitaDB.Client/Queries/Requires/HistogramBehavior.cs b/EvitaDB.Client/Queries/Requires/HistogramBehavior.cs new file mode 100644 index 0000000..850ff63 --- /dev/null +++ b/EvitaDB.Client/Queries/Requires/HistogramBehavior.cs @@ -0,0 +1,18 @@ +namespace EvitaDB.Client.Queries.Requires; + +/// +/// This enumeration describes the behaviour of and calculation. +/// +public enum HistogramBehavior +{ + /// + /// Histogram always contains the number of buckets you asked for. This is the default behaviour. + /// + Standard, + /// + /// Histogram will never contain more buckets than you asked for, but may contain less when the data is scarce and + /// there would be big gaps (empty buckets) between buckets. This leads to more compact histograms, which provide + /// better user experience. + /// + Optimized +} diff --git a/EvitaDB.Client/Queries/Requires/PriceHistogram.cs b/EvitaDB.Client/Queries/Requires/PriceHistogram.cs index 0913ec1..071fb79 100644 --- a/EvitaDB.Client/Queries/Requires/PriceHistogram.cs +++ b/EvitaDB.Client/Queries/Requires/PriceHistogram.cs @@ -17,6 +17,7 @@ namespace EvitaDB.Client.Queries.Requires; public class PriceHistogram : AbstractRequireConstraintLeaf, IExtraResultRequireConstraint { public int RequestedBucketCount => (int) Arguments[0]!; + public HistogramBehavior Behavior => (HistogramBehavior) Arguments[1]!; private PriceHistogram(params object?[] arguments) : base(arguments) { @@ -25,4 +26,9 @@ private PriceHistogram(params object?[] arguments) : base(arguments) public PriceHistogram(int requestedBucketCount) : base(requestedBucketCount) { } + + public PriceHistogram(int requestedBucketCount, HistogramBehavior? behavior) + : base(requestedBucketCount, behavior ?? HistogramBehavior.Standard) + { + } } diff --git a/EvitaDB.Client/Session/IClientContext.cs b/EvitaDB.Client/Session/IClientContext.cs deleted file mode 100644 index 643de79..0000000 --- a/EvitaDB.Client/Session/IClientContext.cs +++ /dev/null @@ -1,134 +0,0 @@ -using EvitaDB.Client.Utils; - -namespace EvitaDB.Client.Session; - -public interface IClientContext -{ - private static readonly ThreadLocal> CurrentClientContext = new(); - - public void ExecuteWithClientAndRequestId(string clientId, string requestId, ThreadStart lambda) - { - Stack? context = CurrentClientContext.Value; - try - { - if (context == null) - { - context = new Stack(); - CurrentClientContext.Value = context; - } - - context.Push(new Context(clientId, requestId)); - lambda.Invoke(); - } - finally - { - context?.Pop(); - } - } - - public void ExecuteWithClientId(string clientId, ThreadStart lambda) - { - Stack? context = CurrentClientContext.Value; - try - { - if (context == null) - { - context = new Stack(); - CurrentClientContext.Value = context; - } - - context.Push(new Context(clientId, null)); - lambda.Invoke(); - } - finally - { - context?.Pop(); - } - } - - public void ExecuteWithRequestId(string requestId, ThreadStart lambda) - { - Stack? context = CurrentClientContext.Value; - try - { - Assert.IsTrue(!(context == null || !context.Any()), - "When changing the request ID, the client ID must be set first!"); - context?.Push(new Context(context.Peek().ClientId, requestId)); - lambda.Invoke(); - } - finally - { - context?.Pop(); - } - } - - public T ExecuteWithClientAndRequestId(string clientId, string requestId, Func lambda) - { - Stack? context = CurrentClientContext.Value; - try - { - if (context == null) - { - context = new Stack(); - CurrentClientContext.Value = context; - } - - context.Push(new Context(clientId, requestId)); - return lambda.Invoke(); - } - finally - { - context?.Pop(); - } - } - - public T ExecuteWithClientId(string clientId, Func lambda) - { - Stack? context = CurrentClientContext.Value; - try - { - if (context == null) - { - context = new Stack(); - CurrentClientContext.Value = context; - } - - context.Push(new Context(clientId, null)); - return lambda.Invoke(); - } - finally - { - context?.Pop(); - } - } - - public T ExecuteWithRequestId(string requestId, Func lambda) - { - Stack? context = CurrentClientContext.Value; - try - { - Assert.IsTrue(!(context == null || !context.Any()), - "When changing the request ID, the client ID must be set first!"); - context?.Push(new Context(context.Peek().ClientId, requestId)); - return lambda.Invoke(); - } - finally - { - context?.Pop(); - } - } - - public string? GetClientId() - { - return CurrentContext?.ClientId; - } - - public string? GetRequestId() - { - return CurrentContext?.RequestId; - } - - private static Context? CurrentContext => CurrentClientContext.Value?.TryPeek(out Context? result) == true ? result : null; - - private record Context(string ClientId, string? RequestId); -} \ No newline at end of file diff --git a/EvitaDB.Client/Utils/ArrayUtils.cs b/EvitaDB.Client/Utils/ArrayUtils.cs index 6b9a979..949fee5 100644 --- a/EvitaDB.Client/Utils/ArrayUtils.cs +++ b/EvitaDB.Client/Utils/ArrayUtils.cs @@ -4,5 +4,5 @@ public static class ArrayUtils { public static bool IsEmpty(object?[]? array) => array is null || array.Length == 0; - public static bool IsEmpty(T[]? array) where T : struct => array is null || array.Length == 0; -} \ No newline at end of file + public static bool IsEmpty(T[]? array) => array is null || array.Length == 0; +} diff --git a/EvitaDB.Client/Utils/OpenTelemetrySetup.cs b/EvitaDB.Client/Utils/OpenTelemetrySetup.cs new file mode 100644 index 0000000..12727d1 --- /dev/null +++ b/EvitaDB.Client/Utils/OpenTelemetrySetup.cs @@ -0,0 +1,36 @@ +using OpenTelemetry; +using OpenTelemetry.Exporter; +using OpenTelemetry.Resources; +using OpenTelemetry.Trace; + +namespace EvitaDB.Client.Utils; + +public class OpenTelemetrySetup : IDisposable +{ + private const string ServiceName = "EvitaDB C# driver"; + + private readonly TracerProvider? _tracerProvider; + + public OpenTelemetrySetup(string traceEndpointUrl, string? protocol) + { + OtlpExportProtocol otlpExportProtocol = Enum.TryParse(protocol, out OtlpExportProtocol parsedProtocol) + ? parsedProtocol + : OtlpExportProtocol.Grpc; + _tracerProvider = Sdk + .CreateTracerProviderBuilder() + .AddSource(ServiceName) + .ConfigureResource(resource => resource.AddService(serviceName: ServiceName)) + .AddGrpcClientInstrumentation(opt => opt.SuppressDownstreamInstrumentation = true) + .AddOtlpExporter(options => + { + options.Endpoint = new Uri(traceEndpointUrl); + options.Protocol = otlpExportProtocol; + }) + .Build(); + } + + public void Dispose() + { + _tracerProvider?.Dispose(); + } +} diff --git a/EvitaDB.QueryValidator/evita-csharp-query-template.txt b/EvitaDB.QueryValidator/evita-csharp-query-template.txt index aede7e9..a7c2e18 100644 --- a/EvitaDB.QueryValidator/evita-csharp-query-template.txt +++ b/EvitaDB.QueryValidator/evita-csharp-query-template.txt @@ -21,6 +21,7 @@ using static EvitaDB.Client.Queries.Requires.PriceContentMode; using static EvitaDB.Client.Queries.Requires.FacetStatisticsDepth; using static EvitaDB.Client.Queries.Requires.QueryPriceMode; using static EvitaDB.Client.Queries.Requires.EmptyHierarchicalEntityBehaviour; +using static EvitaDB.Client.Queries.Requires.HistogramBehavior; public class DynamicClass { diff --git a/EvitaDB.Test/DemoSetupFixture.cs b/EvitaDB.Test/DemoSetupFixture.cs index 41b3fe6..fbd6d25 100644 --- a/EvitaDB.Test/DemoSetupFixture.cs +++ b/EvitaDB.Test/DemoSetupFixture.cs @@ -5,13 +5,14 @@ namespace EvitaDB.Test; public class DemoSetupFixture : BaseSetupFixture { - private static readonly EvitaClientConfiguration EvitaClientConfiguration = new EvitaClientConfiguration.Builder() - .SetHost("demo.evitadb.io") - .SetPort(5556) - .SetUseGeneratedCertificate(false) - .SetUsingTrustedRootCaCertificate(true) - .Build(); - + private static readonly EvitaClientConfiguration EvitaClientConfiguration = + new EvitaClientConfiguration.Builder() + .SetHost("demo.evitadb.io") + .SetPort(5556) + .SetUseGeneratedCertificate(false) + .SetUsingTrustedRootCaCertificate(true) + .Build(); + public override async Task InitializeAsync() { EvitaClient client = await EvitaClient.Create(EvitaClientConfiguration); @@ -34,6 +35,7 @@ public override async Task GetClient() { return evitaClient; } + return await EvitaClient.Create(EvitaClientConfiguration); }