From b9d0f1e2baf6d473c3fd4eda39c7c24fc0f267ab Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Tue, 6 Oct 2020 15:13:18 +0200 Subject: [PATCH] Remove MongoDB provider --- .../Elsa.Persistence.MongoDb.csproj | 36 ----- .../Extensions/ServiceCollectionExtensions.cs | 111 -------------- .../Serialization/JObjectSerializer.cs | 12 -- .../Serialization/JsonSerializerBase.cs | 33 ----- .../Serialization/VariableSerializer.cs | 12 -- .../Services/MongoWorkflowDefinitionStore.cs | 91 ------------ .../Services/MongoWorkflowInstanceStore.cs | 136 ------------------ .../Elsa.Persistence.MongoDb/icon.png | Bin 16374 -> 0 bytes 8 files changed, 431 deletions(-) delete mode 100644 src/providers/Elsa.Persistence.MongoDb/Elsa.Persistence.MongoDb.csproj delete mode 100644 src/providers/Elsa.Persistence.MongoDb/Extensions/ServiceCollectionExtensions.cs delete mode 100644 src/providers/Elsa.Persistence.MongoDb/Serialization/JObjectSerializer.cs delete mode 100644 src/providers/Elsa.Persistence.MongoDb/Serialization/JsonSerializerBase.cs delete mode 100644 src/providers/Elsa.Persistence.MongoDb/Serialization/VariableSerializer.cs delete mode 100644 src/providers/Elsa.Persistence.MongoDb/Services/MongoWorkflowDefinitionStore.cs delete mode 100644 src/providers/Elsa.Persistence.MongoDb/Services/MongoWorkflowInstanceStore.cs delete mode 100644 src/providers/Elsa.Persistence.MongoDb/icon.png diff --git a/src/providers/Elsa.Persistence.MongoDb/Elsa.Persistence.MongoDb.csproj b/src/providers/Elsa.Persistence.MongoDb/Elsa.Persistence.MongoDb.csproj deleted file mode 100644 index 89a3a4506..000000000 --- a/src/providers/Elsa.Persistence.MongoDb/Elsa.Persistence.MongoDb.csproj +++ /dev/null @@ -1,36 +0,0 @@ - - - - netstandard2.0 - latest - 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 MongoDB persistence provider. - - 2019 - https://github.com/elsa-workflows/elsa-core - https://github.com/elsa-workflows/elsa-core - GitHub - elsa, workflows, mongodb - icon.png - - - - - True - - - - - - - - - - - - - - diff --git a/src/providers/Elsa.Persistence.MongoDb/Extensions/ServiceCollectionExtensions.cs b/src/providers/Elsa.Persistence.MongoDb/Extensions/ServiceCollectionExtensions.cs deleted file mode 100644 index 60b32cf9b..000000000 --- a/src/providers/Elsa.Persistence.MongoDb/Extensions/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System; -using Elsa; -using Elsa.Models; -using Elsa.Persistence.MongoDb.Serialization; -using Elsa.Persistence.MongoDb.Services; -using MongoDB.Bson; -using MongoDb.Bson.NodaTime; -using MongoDB.Bson.Serialization; -using MongoDB.Bson.Serialization.Conventions; -using MongoDB.Driver; - -// ReSharper disable once CheckNamespace -namespace Microsoft.Extensions.DependencyInjection -{ - public static class ServiceCollectionExtensions - { - public static ElsaOptions UseMongoDbWorkflowStores( - this ElsaOptions options, - string databaseName, - string connectionString) - { - return options - .AddMongoDbProvider(databaseName, connectionString) - .UseMongoDbWorkflowDefinitionStore(databaseName, connectionString) - .UseMongoDbWorkflowInstanceStore(databaseName, connectionString); - } - - public static ElsaOptions UseMongoDbWorkflowInstanceStore( - this ElsaOptions options, - string databaseName, - string connectionString) - { - options - .AddMongoDbProvider(databaseName, connectionString) - .UseWorkflowInstanceStore(sp => sp.GetRequiredService()) - .Services - .AddMongoDbCollection("WorkflowInstances") - .AddScoped(); - - return options; - } - - public static ElsaOptions UseMongoDbWorkflowDefinitionStore( - this ElsaOptions options, - string databaseName, - string connectionString) - { - options - .AddMongoDbProvider(databaseName, connectionString) - .UseWorkflowDefinitionStore(sp => sp.GetRequiredService()) - .Services - .AddMongoDbCollection("WorkflowDefinitions") - .AddScoped(); - - return options; - } - - public static IServiceCollection AddMongoDbCollection( - this IServiceCollection services, - string collectionName) - { - return services.AddSingleton(sp => CreateCollection(sp, collectionName)); - } - - private static ElsaOptions AddMongoDbProvider( - this ElsaOptions options, - string databaseName, - string connectionString - ) - { - if (options.Services.HasService()) - return options; - - options.Services - .AddTransient() - .AddTransient() - .AddSingleton(sp => - { - NodaTimeSerializers.Register(); - RegisterEnumAsStringConvention(); - BsonSerializer.RegisterSerializer(sp.GetRequiredService()); - BsonSerializer.RegisterSerializer(sp.GetRequiredService()); - return CreateDbClient(connectionString); - }) - .AddSingleton(sp => CreateDatabase(sp, databaseName)); - - return options; - } - - private static IMongoCollection CreateCollection(IServiceProvider serviceProvider, string collectionName) - { - var database = serviceProvider.GetRequiredService(); - return database.GetCollection(collectionName); - } - - private static IMongoDatabase CreateDatabase(IServiceProvider serviceProvider, string databaseName) - { - var client = serviceProvider.GetRequiredService(); - return client.GetDatabase(databaseName); - } - - private static IMongoClient CreateDbClient(string connectionString) => new MongoClient(connectionString); - - private static void RegisterEnumAsStringConvention() - { - var pack = new ConventionPack { new EnumRepresentationConvention(BsonType.String) }; - - ConventionRegistry.Register("EnumStringConvention", pack, _ => true); - } - } -} \ No newline at end of file diff --git a/src/providers/Elsa.Persistence.MongoDb/Serialization/JObjectSerializer.cs b/src/providers/Elsa.Persistence.MongoDb/Serialization/JObjectSerializer.cs deleted file mode 100644 index 12debf91f..000000000 --- a/src/providers/Elsa.Persistence.MongoDb/Serialization/JObjectSerializer.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Elsa.Serialization; -using Newtonsoft.Json.Linq; - -namespace Elsa.Persistence.MongoDb.Serialization -{ - public class JObjectSerializer : JsonSerializerBase - { - public JObjectSerializer(ITokenSerializer serializer) : base(serializer) - { - } - } -} \ No newline at end of file diff --git a/src/providers/Elsa.Persistence.MongoDb/Serialization/JsonSerializerBase.cs b/src/providers/Elsa.Persistence.MongoDb/Serialization/JsonSerializerBase.cs deleted file mode 100644 index 0142287d8..000000000 --- a/src/providers/Elsa.Persistence.MongoDb/Serialization/JsonSerializerBase.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Elsa.Serialization; -using MongoDB.Bson; -using MongoDB.Bson.Serialization; -using MongoDB.Bson.Serialization.Serializers; -using Newtonsoft.Json; - -namespace Elsa.Persistence.MongoDb.Serialization -{ - public abstract class JsonSerializerBase : SerializerBase - { - private readonly ITokenSerializer serializer; - - protected JsonSerializerBase(ITokenSerializer serializer) - { - this.serializer = serializer; - } - - public override T Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) - { - var document = BsonDocumentSerializer.Instance.Deserialize(context); - var value = serializer.Deserialize(document.ToString()); - - return value; - } - - public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, T value) - { - var json = value != null ? serializer.Serialize(value) : null; - var document = json != null ? BsonDocument.Parse(json.ToString(Formatting.None)) : new BsonDocument(); - BsonDocumentSerializer.Instance.Serialize(context, document); - } - } -} \ No newline at end of file diff --git a/src/providers/Elsa.Persistence.MongoDb/Serialization/VariableSerializer.cs b/src/providers/Elsa.Persistence.MongoDb/Serialization/VariableSerializer.cs deleted file mode 100644 index 54144cca1..000000000 --- a/src/providers/Elsa.Persistence.MongoDb/Serialization/VariableSerializer.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Elsa.Models; -using Elsa.Serialization; - -namespace Elsa.Persistence.MongoDb.Serialization -{ - public class VariableSerializer : JsonSerializerBase - { - public VariableSerializer(ITokenSerializer serializer) : base(serializer) - { - } - } -} \ No newline at end of file diff --git a/src/providers/Elsa.Persistence.MongoDb/Services/MongoWorkflowDefinitionStore.cs b/src/providers/Elsa.Persistence.MongoDb/Services/MongoWorkflowDefinitionStore.cs deleted file mode 100644 index 575a87050..000000000 --- a/src/providers/Elsa.Persistence.MongoDb/Services/MongoWorkflowDefinitionStore.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Elsa.Extensions; -using Elsa.Models; -using MongoDB.Driver; -using MongoDB.Driver.Linq; - -namespace Elsa.Persistence.MongoDb.Services -{ - public class MongoWorkflowDefinitionStore : IWorkflowDefinitionStore - { - private readonly IMongoCollection workflowDefinitionCollection; - private readonly IMongoCollection workflowInstanceCollection; - - public MongoWorkflowDefinitionStore( - IMongoCollection workflowDefinitionCollection, - IMongoCollection workflowInstanceCollection) - { - this.workflowDefinitionCollection = workflowDefinitionCollection; - this.workflowInstanceCollection = workflowInstanceCollection; - } - - public async Task SaveAsync( - WorkflowDefinitionVersion definition, - CancellationToken cancellationToken = default) - { - await workflowDefinitionCollection.ReplaceOneAsync( - x => x.Id == definition.Id && x.Version == definition.Version, - definition, - new ReplaceOptions { IsUpsert = true }, - cancellationToken - ); - - return definition; - } - - public async Task AddAsync(WorkflowDefinitionVersion definition, CancellationToken cancellationToken = default) - { - await workflowDefinitionCollection.InsertOneAsync(definition, new InsertOneOptions(), cancellationToken); - return definition; - } - - public Task GetByIdAsync(string id, CancellationToken cancellationToken = default) - { - return workflowDefinitionCollection.AsQueryable().FirstOrDefaultAsync(x => x.Id == id, cancellationToken); - } - - public async Task GetByIdAsync( - string definitionId, - VersionOptions version, - CancellationToken cancellationToken = default) - { - var query = (IMongoQueryable)workflowDefinitionCollection.AsQueryable() - .Where(x => x.DefinitionId == definitionId) - .WithVersion(version); - - return await query.FirstOrDefaultAsync(cancellationToken); - } - - public async Task> ListAsync( - VersionOptions version, - CancellationToken cancellationToken = default) - { - var query = workflowDefinitionCollection.AsQueryable(); - var results = await query.ToListAsync(cancellationToken); - return results.WithVersion(version); - } - - public async Task UpdateAsync(WorkflowDefinitionVersion definition, - CancellationToken cancellationToken) - { - await workflowDefinitionCollection.ReplaceOneAsync( - x => x.Id == definition.Id && x.Version == definition.Version, - definition, - new ReplaceOptions { IsUpsert = false }, - cancellationToken - ); - - return definition; - } - - public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) - { - await workflowInstanceCollection.DeleteManyAsync(x => x.DefinitionId == id, cancellationToken); - var result = await workflowDefinitionCollection.DeleteManyAsync(x => x.DefinitionId == id, cancellationToken); - - return (int) result.DeletedCount; - } - } -} \ No newline at end of file diff --git a/src/providers/Elsa.Persistence.MongoDb/Services/MongoWorkflowInstanceStore.cs b/src/providers/Elsa.Persistence.MongoDb/Services/MongoWorkflowInstanceStore.cs deleted file mode 100644 index 4435ef74b..000000000 --- a/src/providers/Elsa.Persistence.MongoDb/Services/MongoWorkflowInstanceStore.cs +++ /dev/null @@ -1,136 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Elsa.Extensions; -using Elsa.Models; -using MongoDB.Driver; -using MongoDB.Driver.Linq; - -namespace Elsa.Persistence.MongoDb.Services -{ - public class MongoWorkflowInstanceStore : IWorkflowInstanceStore - { - private readonly IMongoCollection collection; - - public MongoWorkflowInstanceStore(IMongoCollection collection) - { - this.collection = collection; - } - - public async Task SaveAsync(WorkflowInstance instance, CancellationToken cancellationToken) - { - await collection.ReplaceOneAsync( - x => x.Id == instance.Id, - instance, - new ReplaceOptions { IsUpsert = true }, - cancellationToken); - - return instance; - } - - public async Task GetByIdAsync( - string id, - CancellationToken cancellationToken) - { - return await collection.AsQueryable().Where(x => x.Id == id).FirstOrDefaultAsync(cancellationToken); - } - - public async Task GetByCorrelationIdAsync( - string correlationId, - CancellationToken cancellationToken = default) - { - return await collection.AsQueryable() - .Where(x => x.CorrelationId == correlationId) - .FirstOrDefaultAsync(cancellationToken); - } - - public async Task> ListByDefinitionAsync( - string definitionId, - CancellationToken cancellationToken) - { - return await collection.AsQueryable() - .Where(x => x.DefinitionId == definitionId) - .OrderByDescending(x => x.CreatedAt) - .ToListAsync(cancellationToken); - } - - public async Task> ListAllAsync(CancellationToken cancellationToken) - { - return await collection - .AsQueryable() - .OrderByDescending(x => x.CreatedAt) - .ToListAsync(cancellationToken); - } - - public async Task> ListByBlockingActivityTagAsync( - string activityType, - string tag, - string correlationId = null, - CancellationToken cancellationToken = default) - { - var query = collection.AsQueryable(); - - query = query.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 = await query.ToListAsync(cancellationToken); - - return instances.GetBlockingActivities(activityType); - } - public async Task> ListByBlockingActivityAsync( - string activityType, - string correlationId = default, - CancellationToken cancellationToken = default) - { - var query = collection.AsQueryable(); - - query = query.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 = await query.ToListAsync(cancellationToken); - - return instances.GetBlockingActivities(activityType); - } - - public async Task> ListByStatusAsync( - string definitionId, - WorkflowStatus status, - CancellationToken cancellationToken) - { - return await collection - .AsQueryable() - .Where(x => x.DefinitionId == definitionId && x.Status == status) - .OrderByDescending(x => x.CreatedAt) - .ToListAsync(cancellationToken); - } - - public async Task> ListByStatusAsync( - WorkflowStatus status, - CancellationToken cancellationToken) - { - return await collection - .AsQueryable() - .Where(x => x.Status == status) - .OrderByDescending(x => x.CreatedAt) - .ToListAsync(cancellationToken); - } - - public async Task DeleteAsync( - string id, - CancellationToken cancellationToken = default) - { - await collection.DeleteOneAsync(x => x.Id == id, cancellationToken); - } - } -} \ No newline at end of file diff --git a/src/providers/Elsa.Persistence.MongoDb/icon.png b/src/providers/Elsa.Persistence.MongoDb/icon.png deleted file mode 100644 index f978a28829e4f03aa270e4f0f2162bb8c41bed2a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16374 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