From bd46f804010ff7bd6234ec02a7ef16ebf08b7522 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Tue, 6 Oct 2020 15:13:02 +0200 Subject: [PATCH] Remove DocumentDB provider --- .../DocumentDbStorage.cs | 57 ----- .../DocumentDbStorageOptions.cs | 62 ------ .../WorkflowDefinitionVersionDocument.cs | 44 ---- .../Documents/WorkflowInstanceDocument.cs | 61 ------ .../Elsa.Persistence.DocumentDb.csproj | 36 --- .../Extensions/ElsaOptionsExtensions.cs | 48 ---- .../WorkflowDefinitionDocumentExtensions.cs | 31 --- .../Helpers/ClientHelper.cs | 205 ------------------ .../Helpers/QueryHelper.cs | 24 -- .../Helpers/TimeHelper.cs | 26 --- .../Mapping/DocumentProfile.cs | 15 -- .../CosmosDbWorkflowDefinitionStore.cs | 114 ---------- .../Services/CosmosDbWorkflowInstanceStore.cs | 173 --------------- .../Elsa.Persistence.DocumentDb/icon.png | Bin 16374 -> 0 bytes 14 files changed, 896 deletions(-) delete mode 100644 src/providers/Elsa.Persistence.DocumentDb/DocumentDbStorage.cs delete mode 100644 src/providers/Elsa.Persistence.DocumentDb/DocumentDbStorageOptions.cs delete mode 100644 src/providers/Elsa.Persistence.DocumentDb/Documents/WorkflowDefinitionVersionDocument.cs delete mode 100644 src/providers/Elsa.Persistence.DocumentDb/Documents/WorkflowInstanceDocument.cs delete mode 100644 src/providers/Elsa.Persistence.DocumentDb/Elsa.Persistence.DocumentDb.csproj delete mode 100644 src/providers/Elsa.Persistence.DocumentDb/Extensions/ElsaOptionsExtensions.cs delete mode 100644 src/providers/Elsa.Persistence.DocumentDb/Extensions/WorkflowDefinitionDocumentExtensions.cs delete mode 100644 src/providers/Elsa.Persistence.DocumentDb/Helpers/ClientHelper.cs delete mode 100644 src/providers/Elsa.Persistence.DocumentDb/Helpers/QueryHelper.cs delete mode 100644 src/providers/Elsa.Persistence.DocumentDb/Helpers/TimeHelper.cs delete mode 100644 src/providers/Elsa.Persistence.DocumentDb/Mapping/DocumentProfile.cs delete mode 100644 src/providers/Elsa.Persistence.DocumentDb/Services/CosmosDbWorkflowDefinitionStore.cs delete mode 100644 src/providers/Elsa.Persistence.DocumentDb/Services/CosmosDbWorkflowInstanceStore.cs delete mode 100644 src/providers/Elsa.Persistence.DocumentDb/icon.png diff --git a/src/providers/Elsa.Persistence.DocumentDb/DocumentDbStorage.cs b/src/providers/Elsa.Persistence.DocumentDb/DocumentDbStorage.cs deleted file mode 100644 index 3da860753..000000000 --- a/src/providers/Elsa.Persistence.DocumentDb/DocumentDbStorage.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Microsoft.Azure.Documents; -using Microsoft.Azure.Documents.Client; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Elsa.Persistence.DocumentDb -{ - public class DocumentDbStorage - { - private DocumentDbStorageOptions Options { get; } - internal DocumentClient Client { get; } - - public DocumentDbStorage(DocumentDbStorageOptions options) - { - Options = options; - - var settings = new JsonSerializerSettings - { - NullValueHandling = NullValueHandling.Ignore, - DateTimeZoneHandling = DateTimeZoneHandling.Utc, - ContractResolver = new CamelCasePropertyNamesContractResolver - { - NamingStrategy = new CamelCaseNamingStrategy(false, false) - } - }; - - var connectionPolicy = ConnectionPolicy.Default; - connectionPolicy.ConnectionMode = Options.ConnectionMode; - connectionPolicy.ConnectionProtocol = Options.ConnectionProtocol; - connectionPolicy.RequestTimeout = Options.RequestTimeout; - connectionPolicy.RetryOptions = new RetryOptions - { - MaxRetryWaitTimeInSeconds = 10, - MaxRetryAttemptsOnThrottledRequests = 5 - }; - - Client = new DocumentClient(options.Url, options.Secret, settings, connectionPolicy); - } - - public override string ToString() => $"DocumentDb Database: {Options.DatabaseName}"; - - public async Task GetCollectionAsync(string collectionName, CancellationToken cancellationToken = default) - { - var database = await Client.CreateDatabaseIfNotExistsAsync(new Database { Id = Options.DatabaseName }); - var databaseUri = UriFactory.CreateDatabaseUri(database.Resource.Id); - - var collection = await Client.CreateDocumentCollectionIfNotExistsAsync( - databaseUri, - new DocumentCollection { Id = collectionName }); - - return UriFactory.CreateDocumentCollectionUri(Options.DatabaseName, collection.Resource.Id); - } - } -} \ No newline at end of file diff --git a/src/providers/Elsa.Persistence.DocumentDb/DocumentDbStorageOptions.cs b/src/providers/Elsa.Persistence.DocumentDb/DocumentDbStorageOptions.cs deleted file mode 100644 index f67fa5019..000000000 --- a/src/providers/Elsa.Persistence.DocumentDb/DocumentDbStorageOptions.cs +++ /dev/null @@ -1,62 +0,0 @@ -using Microsoft.Azure.Documents.Client; -using System; -using System.ComponentModel.DataAnnotations; - -namespace Elsa.Persistence.DocumentDb -{ - public class DocumentDbStorageOptions - { - [Required] - public Uri Url { get; set; } - - [Required] - public string Secret { get; set; } - - [Required] - public string DatabaseName { get; set; } - - /// - /// Get or sets the request timeout for DocumentDB client. Default value set to 30 seconds - /// - public TimeSpan RequestTimeout { get; set; } - - /// - /// Get or set the interval timespan to process expired entries. Default value 15 minutes - /// Expired items under "locks", "jobs", "lists", "sets", "hashs", "counters/aggregated" will be checked - /// - public TimeSpan ExpirationCheckInterval { get; set; } - - /// - /// Get or sets the interval timespan to aggregated the counters. Default value 1 minute - /// - public TimeSpan CountersAggregateInterval { get; set; } - - /// - /// Gets or sets the interval timespan to poll the queue for processing any new jobs. Default value 2 minutes - /// - public TimeSpan QueuePollInterval { get; set; } - - /// - /// Gets or sets the connection mode for the DocumentDB client. Default value is Direct. - /// - public ConnectionMode ConnectionMode { get; set; } - - /// - /// Gets or sets the connection protocol for the DocumentDB client. Default value is TCP. - /// - public Protocol ConnectionProtocol { get; set; } - - /// - /// Create an instance of AzureDocumentDB Storage option with default values - /// - public DocumentDbStorageOptions() - { - RequestTimeout = TimeSpan.FromSeconds(30); - ExpirationCheckInterval = TimeSpan.FromMinutes(2); - CountersAggregateInterval = TimeSpan.FromMinutes(2); - QueuePollInterval = TimeSpan.FromSeconds(15); - ConnectionMode = ConnectionMode.Direct; - ConnectionProtocol = Protocol.Tcp; - } - } -} diff --git a/src/providers/Elsa.Persistence.DocumentDb/Documents/WorkflowDefinitionVersionDocument.cs b/src/providers/Elsa.Persistence.DocumentDb/Documents/WorkflowDefinitionVersionDocument.cs deleted file mode 100644 index ef1ce0274..000000000 --- a/src/providers/Elsa.Persistence.DocumentDb/Documents/WorkflowDefinitionVersionDocument.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Elsa.Models; -using Newtonsoft.Json; -using System.Collections.Generic; - -namespace Elsa.Persistence.DocumentDb.Documents -{ - public class WorkflowDefinitionVersionDocument - { - [JsonProperty(PropertyName = "id")] public string Id { get; set; } - [JsonProperty(PropertyName = "type")] public string Type { get; } = nameof(WorkflowDefinitionVersionDocument); - - [JsonProperty(PropertyName = "definitionId")] - public string DefinitionId { get; set; } - - [JsonProperty(PropertyName = "version")] - public int Version { get; set; } - - [JsonProperty(PropertyName = "name")] public string Name { get; set; } - - [JsonProperty(PropertyName = "description")] - public string Description { get; set; } - - [JsonProperty(PropertyName = "activities")] - public IList Activities { get; set; } - - [JsonProperty(PropertyName = "connections")] - public IList Connections { get; set; } - - [JsonProperty(PropertyName = "variables")] - public Variables Variables { get; set; } - - [JsonProperty(PropertyName = "isSingleton")] - public bool IsSingleton { get; set; } - - [JsonProperty(PropertyName = "isDisabled")] - public bool IsDisabled { get; set; } - - [JsonProperty(PropertyName = "isPublished")] - public bool IsPublished { get; set; } - - [JsonProperty(PropertyName = "isLatest")] - public bool IsLatest { get; set; } - } -} \ No newline at end of file diff --git a/src/providers/Elsa.Persistence.DocumentDb/Documents/WorkflowInstanceDocument.cs b/src/providers/Elsa.Persistence.DocumentDb/Documents/WorkflowInstanceDocument.cs deleted file mode 100644 index c785c6b38..000000000 --- a/src/providers/Elsa.Persistence.DocumentDb/Documents/WorkflowInstanceDocument.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Elsa.Models; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; - -namespace Elsa.Persistence.DocumentDb.Documents -{ - public class WorkflowInstanceDocument - { - [JsonProperty(PropertyName = "id")] public string Id { get; set; } - - [JsonProperty(PropertyName = "definitionId")] - public string DefinitionId { get; set; } - - [JsonProperty(PropertyName = "type")] public string Type { get; } = nameof(WorkflowInstanceDocument); - - [JsonProperty(PropertyName = "version")] - public int Version { get; set; } - - [JsonProperty(PropertyName = "status")] - public WorkflowStatus Status { get; set; } - - [JsonProperty(PropertyName = "correlationId")] - public string CorrelationId { get; set; } - - [JsonProperty(PropertyName = "createdAt")] - public DateTime CreatedAt { get; set; } - - [JsonProperty(PropertyName = "startedAt")] - public DateTime? StartedAt { get; set; } - - [JsonProperty(PropertyName = "finishedAt")] - public DateTime? FinishedAt { get; set; } - - [JsonProperty(PropertyName = "faultedAt")] - public DateTime? FaultedAt { get; set; } - - [JsonProperty(PropertyName = "abortedAt")] - public DateTime? AbortedAt { get; set; } - - [JsonProperty(PropertyName = "activities")] - public IDictionary Activities { get; set; } = new Dictionary(); - - [JsonProperty(PropertyName = "variables")] - public Variables Variables { get; set; } - - [JsonProperty(PropertyName = "input")] public Variable? Input { get; set; } - [JsonProperty(PropertyName = "input")] public Variable? Output { get; set; } - - [JsonProperty(PropertyName = "blockingActivities")] - public HashSet BlockingActivities { get; set; } - - [JsonProperty(PropertyName = "scheduledActivities")] - public Stack ScheduledActivities { get; set; } - - [JsonProperty(PropertyName = "executionLog")] - public ICollection ExecutionLog { get; set; } - - [JsonProperty(PropertyName = "fault")] public WorkflowFault Fault { get; set; } - } -} \ No newline at end of file diff --git a/src/providers/Elsa.Persistence.DocumentDb/Elsa.Persistence.DocumentDb.csproj b/src/providers/Elsa.Persistence.DocumentDb/Elsa.Persistence.DocumentDb.csproj deleted file mode 100644 index 4f603ca45..000000000 --- a/src/providers/Elsa.Persistence.DocumentDb/Elsa.Persistence.DocumentDb.csproj +++ /dev/null @@ -1,36 +0,0 @@ - - - - netstandard2.0 - 8.0 - 1.0.0 - Elsa Contributors - - Elsa is a set of workflow libraries and tools that enable super-fast workflowing capabilities in any .NET Core application. - This package provides a CosmosDb persistence provider. - - 2019 - https://github.com/elsa-workflows/elsa-core - https://github.com/elsa-workflows/elsa-core - GitHub - elsa, workflows, cosmosdb - icon.png - enable - - - - - True - - - - - - - - - - - - - diff --git a/src/providers/Elsa.Persistence.DocumentDb/Extensions/ElsaOptionsExtensions.cs b/src/providers/Elsa.Persistence.DocumentDb/Extensions/ElsaOptionsExtensions.cs deleted file mode 100644 index 30c61b90e..000000000 --- a/src/providers/Elsa.Persistence.DocumentDb/Extensions/ElsaOptionsExtensions.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Elsa.Persistence.DocumentDb.Services; -using Elsa.Extensions; -using Elsa.Mapping; -using Elsa.Persistence.DocumentDb.Mapping; -using Microsoft.Extensions.DependencyInjection; - -namespace Elsa.Persistence.DocumentDb.Extensions -{ - public static class ElsaOptionsExtensions - { - public static ElsaOptions UseCosmosDbWorkflowDefinitionStore(this ElsaOptions options, DocumentDbStorageOptions dbOptions) - { - options - .AddCosmosDbProvider(dbOptions) - .UseWorkflowDefinitionStore(sp => sp.GetRequiredService()); - - options.Services.AddSingleton(); - return options; - } - - public static ElsaOptions UseCosmosDbWorkflowInstanceStore(this ElsaOptions options, DocumentDbStorageOptions dbOptions) - { - options - .AddCosmosDbProvider(dbOptions) - .UseWorkflowInstanceStore(sp => sp.GetRequiredService()); - - options.Services.AddSingleton(); - return options; - } - - private static ElsaOptions AddCosmosDbProvider( - this ElsaOptions options, - DocumentDbStorageOptions documentDbOptions) - { - if (options.HasService()) - return options; - - var storage = new DocumentDbStorage(documentDbOptions); - - options.Services - .AddSingleton(storage) - .AddAutoMapperProfile(ServiceLifetime.Singleton) - .AddAutoMapperProfile(ServiceLifetime.Singleton); - - return options; - } - } -} \ No newline at end of file diff --git a/src/providers/Elsa.Persistence.DocumentDb/Extensions/WorkflowDefinitionDocumentExtensions.cs b/src/providers/Elsa.Persistence.DocumentDb/Extensions/WorkflowDefinitionDocumentExtensions.cs deleted file mode 100644 index ab04569a2..000000000 --- a/src/providers/Elsa.Persistence.DocumentDb/Extensions/WorkflowDefinitionDocumentExtensions.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Elsa.Models; -using Elsa.Persistence.DocumentDb.Documents; -using System.Linq; - -namespace Elsa.Persistence.DocumentDb.Extensions -{ - public static class WorkflowDefinitionDocumentExtensions - { - public static IQueryable WithVersion( - this IQueryable query, - VersionOptions version) - { - if (version.IsDraft) - query = query.Where(x => !x.IsPublished); - else if (version.IsLatest) - query = query.Where(x => x.IsLatest); - else if (version.IsPublished) - query = query.Where(x => x.IsPublished); - else if (version.IsLatestOrPublished) - query = query.Where(x => x.IsPublished || x.IsLatest); - else if (version.AllVersions) - { - // Nothing to filter. - } - else if (version.Version > 0) - query = query.Where(x => x.Version == version.Version); - - return query.OrderByDescending(x => x.Version); - } - } -} \ No newline at end of file diff --git a/src/providers/Elsa.Persistence.DocumentDb/Helpers/ClientHelper.cs b/src/providers/Elsa.Persistence.DocumentDb/Helpers/ClientHelper.cs deleted file mode 100644 index 092a7d63d..000000000 --- a/src/providers/Elsa.Persistence.DocumentDb/Helpers/ClientHelper.cs +++ /dev/null @@ -1,205 +0,0 @@ -using Microsoft.Azure.Documents; -using Microsoft.Azure.Documents.Client; -using Microsoft.Azure.Documents.Linq; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Elsa.Persistence.DocumentDb.Helpers -{ - internal static class ClientHelper - { - /// - /// Creates a document as an asynchronous operation in the Azure Cosmos DB service. - /// - /// - /// the URI of the document collection to create the document in. - /// the document object. - /// The request options for the request. - /// Disables the automatic id generation, will throw an exception if id is missing. - /// (Optional) representing request cancellation. - /// - internal static Task> CreateDocumentWithRetriesAsync( - this DocumentClient client, - Uri documentCollectionUri, - object document, - RequestOptions options = null, - bool disableAutomaticIdGeneration = false, - CancellationToken cancellationToken = default) - { - return Task.Run( - async () => await client.ExecuteWithRetries( - () => client.CreateDocumentAsync( - documentCollectionUri, - document, - options, - disableAutomaticIdGeneration, - cancellationToken)), - cancellationToken); - } - - /// - /// Reads a as a generic type T from the Azure Cosmos DB service as an asynchronous operation. - /// - /// - /// - /// A URI to the Document resource to be read. - /// The request options for the request. - /// (Optional) representing request cancellation. - /// - internal static Task> ReadDocumentWithRetriesAsync( - this DocumentClient client, - Uri documentUri, - RequestOptions options = null, - CancellationToken cancellationToken = default) - { - return Task.Run( - async () => await client.ExecuteWithRetries( - () => client.ReadDocumentAsync(documentUri, options, cancellationToken)), - cancellationToken); - } - - /// - /// Upserts a document as an asynchronous operation in the Azure Cosmos DB service. - /// - /// - /// the URI of the document collection to upsert the document in. - /// The document object. - /// The request options for the request. - /// Disables the automatic id generation, will throw an exception if id is missing. - /// (Optional) representing request cancellation. - internal static Task> UpsertDocumentWithRetriesAsync( - this DocumentClient client, - Uri documentCollectionUri, - object document, - RequestOptions options = null, - bool disableAutomaticIdGeneration = false, - CancellationToken cancellationToken = default) - { - return Task.Run( - async () => await client.ExecuteWithRetries( - () => client.UpsertDocumentAsync( - documentCollectionUri, - document, - options, - disableAutomaticIdGeneration, - cancellationToken)), - cancellationToken); - } - - /// - /// Delete a document as an asynchronous operation from the Azure Cosmos DB service. - /// - /// - /// The URI of the document to delete. - /// The request options for the request. - /// (Optional) representing request cancellation. - internal static Task> DeleteDocumentWithRetriesAsync( - this DocumentClient client, - Uri documentUri, - RequestOptions options = null, - CancellationToken cancellationToken = default) - { - return Task.Run( - async () => await client.ExecuteWithRetries( - () => client.DeleteDocumentAsync(documentUri, options, cancellationToken)), - cancellationToken); - } - - /// - /// Replaces a document as an asynchronous operation in the Azure Cosmos DB service. - /// - /// - /// The URI of the document to be updated. - /// The updated document. - /// The request options for the request. - /// (Optional) representing request cancellation. - /// - internal static Task> ReplaceDocumentWithRetriesAsync( - this DocumentClient client, - Uri documentUri, - object document, - RequestOptions options = null, - CancellationToken cancellationToken = default) - { - return Task.Run( - async () => await client.ExecuteWithRetries( - () => client.ReplaceDocumentAsync(documentUri, document, options, cancellationToken)), - cancellationToken); - } - - /// - /// Executes a stored procedure against a collection as an asynchronous operation from the Azure Cosmos DB service. - /// - /// - /// - /// The URI of the stored procedure to be executed. - /// The parameters for the stored procedure execution. - /// - internal static Task> ExecuteStoredProcedureWithRetriesAsync( - this DocumentClient client, - Uri storedProcedureUri, - params object[] procedureParams) - { - return Task.Run( - async () => await client.ExecuteWithRetries( - () => client.ExecuteStoredProcedureAsync(storedProcedureUri, procedureParams))); - } - - /// - /// Execute the function with retries on throttle - /// - internal static async Task> ExecuteNextWithRetriesAsync(this IDocumentQuery query) - { - while (true) - { - TimeSpan timeSpan; - - try - { - return await query.ExecuteNextAsync(); - } - catch (DocumentClientException ex) when (ex.StatusCode != null && (int) ex.StatusCode == 429) - { - timeSpan = ex.RetryAfter; - } - catch (AggregateException ex) when (ex.InnerException is DocumentClientException de && - de.StatusCode != null && (int) de.StatusCode == 429) - { - timeSpan = de.RetryAfter; - } - - await Task.Delay(timeSpan); - } - } - - /// - /// Execute the function with retries on throttle - /// - internal static async Task ExecuteWithRetries( - this DocumentClient client, - Func> function) - { - while (true) - { - TimeSpan timeSpan; - - try - { - return await function(); - } - catch (DocumentClientException ex) when (ex.StatusCode != null && (int) ex.StatusCode == 429) - { - timeSpan = ex.RetryAfter; - } - catch (AggregateException ex) when (ex.InnerException is DocumentClientException de && - de.StatusCode != null && (int) de.StatusCode == 429) - { - timeSpan = de.RetryAfter; - } - - await Task.Delay(timeSpan); - } - } - } -} \ No newline at end of file diff --git a/src/providers/Elsa.Persistence.DocumentDb/Helpers/QueryHelper.cs b/src/providers/Elsa.Persistence.DocumentDb/Helpers/QueryHelper.cs deleted file mode 100644 index fd609139d..000000000 --- a/src/providers/Elsa.Persistence.DocumentDb/Helpers/QueryHelper.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Microsoft.Azure.Documents.Linq; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Elsa.Persistence.DocumentDb.Helpers -{ - internal static class QueryHelper - { - internal static async Task> ToQueryResultAsync(this IQueryable source) - { - var query = source.AsDocumentQuery(); - var results = new List(); - - while (query.HasMoreResults) - { - var nextResults = await Task.Run(async () => await query.ExecuteNextWithRetriesAsync()); - results.AddRange(nextResults); - } - - return results; - } - } -} diff --git a/src/providers/Elsa.Persistence.DocumentDb/Helpers/TimeHelper.cs b/src/providers/Elsa.Persistence.DocumentDb/Helpers/TimeHelper.cs deleted file mode 100644 index a6525f243..000000000 --- a/src/providers/Elsa.Persistence.DocumentDb/Helpers/TimeHelper.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Globalization; - -namespace Elsa.Persistence.DocumentDb.Helpers -{ - internal static class TimeHelper - { - private static readonly DateTime EpochDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); - - internal static int ToEpoch(this DateTime date) - { - if (date.Equals(DateTime.MinValue)) return int.MinValue; - var epochTimeSpan = date - EpochDateTime; - return (int) epochTimeSpan.TotalSeconds; - } - - internal static DateTime ToDateTime(this int totalSeconds) => EpochDateTime.AddSeconds(totalSeconds); - - internal static string TryParseToEpoch(this string s) - { - return DateTime.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var date) - ? date.ToEpoch().ToString(CultureInfo.InvariantCulture) - : s; - } - } -} \ No newline at end of file diff --git a/src/providers/Elsa.Persistence.DocumentDb/Mapping/DocumentProfile.cs b/src/providers/Elsa.Persistence.DocumentDb/Mapping/DocumentProfile.cs deleted file mode 100644 index df3c3f431..000000000 --- a/src/providers/Elsa.Persistence.DocumentDb/Mapping/DocumentProfile.cs +++ /dev/null @@ -1,15 +0,0 @@ -using AutoMapper; -using Elsa.Models; -using Elsa.Persistence.DocumentDb.Documents; - -namespace Elsa.Persistence.DocumentDb.Mapping -{ - public class DocumentProfile : Profile - { - public DocumentProfile() - { - CreateMap().ReverseMap(); - CreateMap().ReverseMap(); - } - } -} diff --git a/src/providers/Elsa.Persistence.DocumentDb/Services/CosmosDbWorkflowDefinitionStore.cs b/src/providers/Elsa.Persistence.DocumentDb/Services/CosmosDbWorkflowDefinitionStore.cs deleted file mode 100644 index 01c9b591f..000000000 --- a/src/providers/Elsa.Persistence.DocumentDb/Services/CosmosDbWorkflowDefinitionStore.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using AutoMapper; -using Elsa.Models; -using Elsa.Persistence.DocumentDb.Documents; -using Elsa.Persistence.DocumentDb.Extensions; -using Elsa.Persistence.DocumentDb.Helpers; - -namespace Elsa.Persistence.DocumentDb.Services -{ - public class CosmosDbWorkflowDefinitionStore : IWorkflowDefinitionStore - { - private readonly IMapper mapper; - private readonly DocumentDbStorage storage; - private Uri? collectionUrl; - - public CosmosDbWorkflowDefinitionStore(DocumentDbStorage storage, IMapper mapper) - { - this.storage = storage; - this.mapper = mapper; - collectionUrl = default; - } - - public async Task AddAsync(WorkflowDefinitionVersion definition, CancellationToken cancellationToken = default) - { - var document = Map(definition); - var client = storage.Client; - var collectionUrl = await GetCollectionUriAsync(cancellationToken); - await client.CreateDocumentWithRetriesAsync(collectionUrl, document, cancellationToken: cancellationToken); - return Map(document); - } - - public async Task GetByIdAsync(string id, CancellationToken cancellationToken = default) - { - var client = storage.Client; - var collectionUrl = await GetCollectionUriAsync(cancellationToken); - var query = client.CreateDocumentQuery(collectionUrl).Where(c => c.Id == id); - var document = query.FirstOrDefault(); - return Map(document); - } - - public async Task GetByIdAsync(string definitionId, VersionOptions version, CancellationToken cancellationToken = default) - { - var client = storage.Client; - var collectionUrl = await GetCollectionUriAsync(cancellationToken); - var query = client.CreateDocumentQuery(collectionUrl) - .Where(c => c.DefinitionId == definitionId).WithVersion(version); - var document = query.AsEnumerable().FirstOrDefault(); - return Map(document); - } - - public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) - { - var client = storage.Client; - var collectionUrl = await GetCollectionUriAsync(cancellationToken); - var workflowDefinitionDocuments = await client.CreateDocumentQuery(collectionUrl).Where(c => c.DefinitionId == id).ToQueryResultAsync(); - foreach (var record in workflowDefinitionDocuments) - { - await client.DeleteDocumentAsync(record.Id, cancellationToken: cancellationToken); - } - return workflowDefinitionDocuments.Count; - } - - public async Task> ListAsync(VersionOptions version, CancellationToken cancellationToken = default) - { - var client = storage.Client; - var collectionUrl = await GetCollectionUriAsync(cancellationToken); - var query = client - .CreateDocumentQuery(collectionUrl) - .WithVersion(version).ToList(); - - return mapper.Map>(query); - } - - public async Task SaveAsync(WorkflowDefinitionVersion definition, CancellationToken cancellationToken = default) - { - var document = Map(definition); - var client = storage.Client; - var collectionUrl = await GetCollectionUriAsync(cancellationToken); - await client.UpsertDocumentWithRetriesAsync(collectionUrl, document, cancellationToken: cancellationToken); - return definition; - } - - public async Task UpdateAsync(WorkflowDefinitionVersion definition, CancellationToken cancellationToken = default) - { - var document = Map(definition); - var client = storage.Client; - var collectionUrl = await GetCollectionUriAsync(cancellationToken); - await client.UpsertDocumentWithRetriesAsync(collectionUrl, document, cancellationToken: cancellationToken); - return Map(document); - } - - private async Task GetCollectionUriAsync(CancellationToken cancellationToken) - { - if (collectionUrl == null) - collectionUrl = await storage.GetCollectionAsync("WorkflowDefinitions", cancellationToken); - - return collectionUrl; - } - - private WorkflowDefinitionVersionDocument Map(WorkflowDefinitionVersion source) - { - return mapper.Map(source); - } - - private WorkflowDefinitionVersion Map(WorkflowDefinitionVersionDocument source) - { - return mapper.Map(source); - } - } -} diff --git a/src/providers/Elsa.Persistence.DocumentDb/Services/CosmosDbWorkflowInstanceStore.cs b/src/providers/Elsa.Persistence.DocumentDb/Services/CosmosDbWorkflowInstanceStore.cs deleted file mode 100644 index 4aa641b45..000000000 --- a/src/providers/Elsa.Persistence.DocumentDb/Services/CosmosDbWorkflowInstanceStore.cs +++ /dev/null @@ -1,173 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using AutoMapper; -using Elsa.Extensions; -using Elsa.Models; -using Elsa.Persistence.DocumentDb.Documents; -using Elsa.Persistence.DocumentDb.Helpers; - -namespace Elsa.Persistence.DocumentDb.Services -{ - public class CosmosDbWorkflowInstanceStore : IWorkflowInstanceStore - { - private readonly IMapper mapper; - private readonly DocumentDbStorage storage; - private Uri? collectionUrl; - - public CosmosDbWorkflowInstanceStore(DocumentDbStorage storage, IMapper mapper) - { - this.storage = storage; - this.mapper = mapper; - collectionUrl = default; - } - - public async Task DeleteAsync( - string id, - CancellationToken cancellationToken = default) - { - var client = storage.Client; - await client.DeleteDocumentAsync(id, cancellationToken: cancellationToken); - } - - public async Task GetByCorrelationIdAsync( - string correlationId, - CancellationToken cancellationToken = default) - { - var client = storage.Client; - var collectionUrl = await GetCollectionUriAsync(cancellationToken); - var query = client.CreateDocumentQuery(collectionUrl) - .Where(c => c.CorrelationId == correlationId); - var document = query.AsEnumerable().FirstOrDefault(); - return Map(document); - } - - public async Task GetByIdAsync( - string id, - CancellationToken cancellationToken = default) - { - var client = storage.Client; - var collectionUrl = await GetCollectionUriAsync(cancellationToken); - var query = client.CreateDocumentQuery(collectionUrl) - .Where(c => c.Id == id); - var document = query.AsEnumerable().FirstOrDefault(); - return Map(document); - } - - public async Task> ListAllAsync(CancellationToken cancellationToken = default) - { - var client = storage.Client; - var collectionUrl = await GetCollectionUriAsync(cancellationToken); - var query = client - .CreateDocumentQuery(collectionUrl) - .OrderByDescending(x => x.CreatedAt); - return mapper.Map>(query); - } - public async Task> ListByBlockingActivityTagAsync( - string activityType, - string tag, - string? correlationId = null, - CancellationToken cancellationToken = default) - { - var client = storage.Client; - var collectionUrl = await GetCollectionUriAsync(cancellationToken); - var query = client - .CreateDocumentQuery(collectionUrl) - .Where(x => x.Status == WorkflowStatus.Suspended); - - if (!string.IsNullOrWhiteSpace(correlationId)) - query = query.Where(x => x.CorrelationId == correlationId); - - query = query.Where(x => x.BlockingActivities.Any(y => y.ActivityType == activityType && y.Tag == tag)); - query = query.OrderByDescending(x => x.CreatedAt); - - var instances = Map(query.ToList()); - return instances.GetBlockingActivities(activityType); - } - - public async Task> ListByBlockingActivityAsync( - string activityType, - string? correlationId = null, - CancellationToken cancellationToken = default) - { - var client = storage.Client; - var collectionUrl = await GetCollectionUriAsync(cancellationToken); - var query = client - .CreateDocumentQuery(collectionUrl) - .Where(x => x.Status == WorkflowStatus.Suspended); - - if (!string.IsNullOrWhiteSpace(correlationId)) - query = query.Where(x => x.CorrelationId == correlationId); - - query = query.Where(x => x.BlockingActivities.Any(y => y.ActivityType == activityType)); - query = query.OrderByDescending(x => x.CreatedAt); - - var instances = Map(query.ToList()); - return instances.GetBlockingActivities(activityType); - } - - public async Task> ListByDefinitionAsync( - string definitionId, - CancellationToken cancellationToken = default) - { - var client = storage.Client; - var collectionUrl = await GetCollectionUriAsync(cancellationToken); - var query = client.CreateDocumentQuery(collectionUrl) - .Where(c => c.DefinitionId == definitionId) - .OrderByDescending(x => x.CreatedAt); - return Map(query.ToList()); - } - - public async Task> ListByStatusAsync( - string definitionId, - WorkflowStatus status, - CancellationToken cancellationToken = default) - { - var client = storage.Client; - var collectionUrl = await GetCollectionUriAsync(cancellationToken); - var query = client.CreateDocumentQuery(collectionUrl) - .Where(c => c.DefinitionId == definitionId && c.Status == status) - .OrderByDescending(x => x.CreatedAt); - return Map(query.ToList()); - } - - public async Task> ListByStatusAsync(WorkflowStatus status, CancellationToken cancellationToken = default) - { - var client = storage.Client; - var collectionUrl = await GetCollectionUriAsync(cancellationToken); - var query = client.CreateDocumentQuery(collectionUrl) - .Where(c => c.Status == status) - .OrderByDescending(x => x.CreatedAt); - return Map(query.ToList()); - } - - public async Task SaveAsync(WorkflowInstance instance, CancellationToken cancellationToken = default) - { - var document = Map(instance); - var client = storage.Client; - var collectionUrl = await GetCollectionUriAsync(cancellationToken); - var response = await client.UpsertDocumentWithRetriesAsync( - collectionUrl, - document, - cancellationToken: cancellationToken); - - document = (dynamic)response.Resource; - return Map(document); - } - - private async Task GetCollectionUriAsync(CancellationToken cancellationToken) - { - if (collectionUrl == null) - collectionUrl = await storage.GetCollectionAsync("WorkflowInstances", cancellationToken); - - return collectionUrl; - } - - private WorkflowInstanceDocument Map(WorkflowInstance source) => mapper.Map(source); - private WorkflowInstance Map(WorkflowInstanceDocument source) => mapper.Map(source); - - private IEnumerable Map(IEnumerable source) => mapper.Map>(source); - } -} \ No newline at end of file diff --git a/src/providers/Elsa.Persistence.DocumentDb/icon.png b/src/providers/Elsa.Persistence.DocumentDb/icon.png deleted file mode 100644 index f978a28829e4f03aa270e4f0f2162bb8c41bed2a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16374 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