diff --git a/REstate.sln b/REstate.sln
index f1e0ecc..5cf1b4a 100644
--- a/REstate.sln
+++ b/REstate.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
-VisualStudioVersion = 15.0.27130.2003
+VisualStudioVersion = 15.0.27130.2020
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "REstate", "src\REstate\REstate.csproj", "{8B02FF53-A9F3-4004-8CDC-32831070957D}"
EndProject
@@ -29,6 +29,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "REstate.Remote.Tests", "tes
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semaphore", "src\Examples\Semaphore\Semaphore.csproj", "{F15E390F-EFCF-4848-96C8-597BD75B7F9C}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "REstate.Engine.Repositories.EntityFrameworkCore", "src\REstate.Engine.Repositories.EntityFrameworkCore\REstate.Engine.Repositories.EntityFrameworkCore.csproj", "{3E0263FE-540E-401E-818A-CB51350D30C2}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "REstate.Engine.Repositories.EntityFrameworkCore.Tests", "test\REstate.Engine.Repositories.EntityFrameworkCore.Tests\REstate.Engine.Repositories.EntityFrameworkCore.Tests.csproj", "{5F424F7B-4840-414D-9FA3-7700D81AD898}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -71,6 +75,14 @@ Global
{F15E390F-EFCF-4848-96C8-597BD75B7F9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F15E390F-EFCF-4848-96C8-597BD75B7F9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F15E390F-EFCF-4848-96C8-597BD75B7F9C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3E0263FE-540E-401E-818A-CB51350D30C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3E0263FE-540E-401E-818A-CB51350D30C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3E0263FE-540E-401E-818A-CB51350D30C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3E0263FE-540E-401E-818A-CB51350D30C2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5F424F7B-4840-414D-9FA3-7700D81AD898}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5F424F7B-4840-414D-9FA3-7700D81AD898}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5F424F7B-4840-414D-9FA3-7700D81AD898}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5F424F7B-4840-414D-9FA3-7700D81AD898}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -86,6 +98,8 @@ Global
{7E243087-D506-4D89-BB66-83C6DE063778} = {88B4B54C-3DA1-40D2-8DCB-0181DD035955}
{C64BFCFB-3BF8-4662-A274-7ACC324232CD} = {88B4B54C-3DA1-40D2-8DCB-0181DD035955}
{F15E390F-EFCF-4848-96C8-597BD75B7F9C} = {20BCC0A3-8FEB-4EFF-A175-22D1E3E4E233}
+ {3E0263FE-540E-401E-818A-CB51350D30C2} = {90E8D167-048D-467B-81D5-1007247226A3}
+ {5F424F7B-4840-414D-9FA3-7700D81AD898} = {88B4B54C-3DA1-40D2-8DCB-0181DD035955}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0C35B35D-40C1-4521-BF0A-C5A6D7BFF4CD}
diff --git a/src/REstate.Engine.Connectors.AzureServiceBus/REstate.Engine.Connectors.AzureServiceBus.csproj b/src/REstate.Engine.Connectors.AzureServiceBus/REstate.Engine.Connectors.AzureServiceBus.csproj
index 292531a..f206a4d 100644
--- a/src/REstate.Engine.Connectors.AzureServiceBus/REstate.Engine.Connectors.AzureServiceBus.csproj
+++ b/src/REstate.Engine.Connectors.AzureServiceBus/REstate.Engine.Connectors.AzureServiceBus.csproj
@@ -6,7 +6,7 @@
-
+
diff --git a/src/REstate.Engine.Repositories.EntityFrameworkCore/EntityFrameworkCoreEngineRepositoryContext.cs b/src/REstate.Engine.Repositories.EntityFrameworkCore/EntityFrameworkCoreEngineRepositoryContext.cs
new file mode 100644
index 0000000..c4f9088
--- /dev/null
+++ b/src/REstate.Engine.Repositories.EntityFrameworkCore/EntityFrameworkCoreEngineRepositoryContext.cs
@@ -0,0 +1,403 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using MessagePack;
+using MessagePack.Resolvers;
+using Microsoft.EntityFrameworkCore;
+using REstate.Schematics;
+
+namespace REstate.Engine.Repositories.EntityFrameworkCore
+{
+ public class EntityFrameworkCoreEngineRepositoryContext
+ : IEngineRepositoryContext
+ , ISchematicRepository
+ , IMachineRepository
+ {
+ public EntityFrameworkCoreEngineRepositoryContext(REstateDbContext dbContext)
+ {
+ DbContext = dbContext;
+ }
+
+
+ public ISchematicRepository Schematics => this;
+ public IMachineRepository Machines => this;
+
+ protected REstateDbContext DbContext { get; }
+
+ ///
+ /// Retrieves a previously stored Schematic by name.
+ ///
+ /// The name of the Schematic
+ ///
+ /// Thrown if is null.
+ /// Thrown when no matching Schematic was found for the given name.
+ public async Task> RetrieveSchematicAsync(string schematicName, CancellationToken cancellationToken = default)
+ {
+ if (schematicName == null) throw new ArgumentNullException(nameof(schematicName));
+
+ EntityFrameworkCoreSchematic result;
+ try
+ {
+ result = await DbContext.Schematics.SingleAsync(
+ schematicRecord => schematicRecord.SchematicName == schematicName,
+ cancellationToken).ConfigureAwait(false);
+ }
+ catch (Exception)
+ {
+ throw new SchematicDoesNotExistException(schematicName);
+ }
+
+ var schematic = MessagePackSerializer.Deserialize>(
+ bytes: MessagePackSerializer.FromJson(result.SchematicJson),
+ resolver: ContractlessStandardResolver.Instance);
+
+ return schematic;
+ }
+
+ ///
+ /// Stores a Schematic, using its SchematicName as the key.
+ ///
+ /// The Schematic to store
+ ///
+ /// Thrown if is null.
+ /// Thrown if has a null SchematicName property.
+ public async Task> StoreSchematicAsync(Schematic schematic, CancellationToken cancellationToken = default)
+ {
+ if (schematic == null) throw new ArgumentNullException(nameof(schematic));
+ if (schematic.SchematicName == null) throw new ArgumentException("Schematic must have a name to be stored.", nameof(schematic));
+
+
+ var schematicJson = MessagePackSerializer.ToJson(
+ obj: schematic,
+ resolver: ContractlessStandardResolver.Instance);
+
+ var record = new EntityFrameworkCoreSchematic
+ {
+ SchematicName = schematic.SchematicName,
+ SchematicJson = schematicJson
+ };
+
+ DbContext.Schematics.Add(record);
+
+ await DbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
+
+ return schematic;
+ }
+
+ ///
+ /// Creates a new Machine from a provided Schematic.
+ ///
+ /// The name of the stored Schematic
+ /// The Id of Machine to create; if null, an Id will be generated.
+ /// Related metadata for the Machine
+ ///
+ /// Thrown if is null.
+ public async Task> CreateMachineAsync(string schematicName, string machineId, IDictionary metadata,
+ CancellationToken cancellationToken = default)
+ {
+ if (schematicName == null) throw new ArgumentNullException(nameof(schematicName));
+
+ var schematic = await RetrieveSchematicAsync(schematicName, cancellationToken).ConfigureAwait(false);
+
+ return await CreateMachineAsync(schematic, machineId, metadata, cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ /// Creates a new Machine from a provided Schematic.
+ ///
+ /// The Schematic of the Machine
+ /// The Id of Machine to create; if null, an Id will be generated.
+ /// Related metadata for the Machine
+ ///
+ /// Thrown if is null.
+ /// Thrown when no matching Schematic was found for the given name.
+ public async Task> CreateMachineAsync(
+ Schematic schematic,
+ string machineId,
+ IDictionary metadata,
+ CancellationToken cancellationToken = default)
+ {
+ if (schematic == null) throw new ArgumentNullException(nameof(schematic));
+
+ var id = machineId ?? Guid.NewGuid().ToString();
+
+ var schematicJson = MessagePackSerializer.ToJson(
+ obj: schematic,
+ resolver: ContractlessStandardResolver.Instance);
+
+ var stateJson = MessagePackSerializer.ToJson(
+ obj: schematic.InitialState,
+ resolver: ContractlessStandardResolver.Instance);
+
+ string metadataJson = null;
+ if (metadata != null)
+ metadataJson = MessagePackSerializer.ToJson(
+ obj: metadata);
+
+ var commitTag = Guid.NewGuid();
+ var updatedTime = DateTimeOffset.UtcNow;
+
+ var record = new EntityFrameworkCoreMachineStatus
+ {
+ MachineId = id,
+ SchematicJson = schematicJson,
+ StateJson = stateJson,
+ CommitTag = commitTag,
+ UpdatedTime = updatedTime,
+ MetadataJson = metadataJson
+ };
+
+ DbContext.Machines.Add(record);
+
+ await DbContext.SaveChangesAsync(cancellationToken);
+
+ return new MachineStatus
+ {
+ MachineId = id,
+ Schematic = schematic.Clone(),
+ State = schematic.InitialState,
+ Metadata = metadata,
+ CommitTag = commitTag,
+ UpdatedTime = updatedTime
+ };
+ }
+
+ public async Task>> BulkCreateMachinesAsync(
+ Schematic schematic,
+ IEnumerable> metadata,
+ CancellationToken cancellationToken = default)
+ {
+ if (schematic == null) throw new ArgumentNullException(nameof(schematic));
+
+ var schematicJson = MessagePackSerializer.ToJson(
+ obj: schematic,
+ resolver: ContractlessStandardResolver.Instance);
+
+ var stateJson = MessagePackSerializer.ToJson(
+ obj: schematic.InitialState,
+ resolver: ContractlessStandardResolver.Instance);
+
+ var commitTag = Guid.NewGuid();
+ var updatedTime = DateTimeOffset.UtcNow;
+
+ var records = new List();
+ var machineStatuses = new List>();
+
+ foreach (var dictionary in metadata)
+ {
+ var machineId = Guid.NewGuid().ToString();
+
+ string metadataJson = null;
+ if (dictionary != null)
+ metadataJson = MessagePackSerializer.ToJson(
+ obj: dictionary);
+
+ records.Add(new EntityFrameworkCoreMachineStatus
+ {
+ MachineId = machineId,
+ SchematicJson = schematicJson,
+ StateJson = stateJson,
+ CommitTag = commitTag,
+ UpdatedTime = updatedTime,
+ MetadataJson = metadataJson
+ });
+
+ machineStatuses.Add(new MachineStatus
+ {
+ MachineId = machineId,
+ Schematic = schematic.Clone(),
+ State = schematic.InitialState,
+ Metadata = dictionary,
+ CommitTag = commitTag,
+ UpdatedTime = updatedTime
+ });
+ }
+
+ await DbContext.AddRangeAsync(records, cancellationToken);
+
+ await DbContext.SaveChangesAsync(cancellationToken);
+
+ return machineStatuses;
+ }
+
+ public async Task>> BulkCreateMachinesAsync(
+ string schematicName,
+ IEnumerable> metadata,
+ CancellationToken cancellationToken = default)
+ {
+ var schematic = await RetrieveSchematicAsync(schematicName, cancellationToken).ConfigureAwait(false);
+
+ return await BulkCreateMachinesAsync(schematic, metadata, cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ /// Deletes a Machine.
+ ///
+ ///
+ /// Does not throw an exception if a matching Machine was not found.
+ ///
+ /// The Id of the Machine to delete
+ ///
+ /// Thrown if is null.
+ public async Task DeleteMachineAsync(string machineId, CancellationToken cancellationToken = default)
+ {
+ if (machineId == null) throw new ArgumentNullException(nameof(machineId));
+
+ var machineRecord = await DbContext.Machines
+ .SingleOrDefaultAsync(
+ status => status.MachineId == machineId,
+ cancellationToken).ConfigureAwait(false);
+
+ if (machineRecord != null)
+ {
+ DbContext.Machines.Remove(machineRecord);
+
+ await DbContext.SaveChangesAsync(cancellationToken);
+ }
+ }
+
+ ///
+ /// Retrieves the record for a Machine Status.
+ ///
+ /// The Id of the Machine
+ ///
+ /// Thrown if is null.
+ /// Thrown when no matching MachineId was found.
+ public async Task> GetMachineStatusAsync(
+ string machineId,
+ CancellationToken cancellationToken = default)
+ {
+ if (machineId == null) throw new ArgumentNullException(nameof(machineId));
+
+ var machineRecord = await DbContext.Machines
+ .SingleOrDefaultAsync(
+ status => status.MachineId == machineId,
+ cancellationToken).ConfigureAwait(false);
+
+ if(machineRecord == null) throw new MachineDoesNotExistException(machineId);
+
+ var schematic = MessagePackSerializer.Deserialize>(
+ bytes: MessagePackSerializer.FromJson(machineRecord.SchematicJson),
+ resolver: ContractlessStandardResolver.Instance);
+
+ var state = MessagePackSerializer.Deserialize(
+ bytes: MessagePackSerializer.FromJson(machineRecord.StateJson),
+ resolver: ContractlessStandardResolver.Instance);
+
+ IDictionary metadata = null;
+ if(machineRecord.MetadataJson != null)
+ metadata = MessagePackSerializer.Deserialize>(
+ bytes: MessagePackSerializer.FromJson(machineRecord.MetadataJson));
+
+ return new MachineStatus
+ {
+ MachineId = machineId,
+ Schematic = schematic,
+ State = state,
+ Metadata = metadata,
+ CommitTag = machineRecord.CommitTag,
+ UpdatedTime = machineRecord.UpdatedTime
+ };
+ }
+
+ ///
+ /// Updates the Status record of a Machine
+ ///
+ /// The Id of the Machine
+ /// The state to which the Status is set.
+ ///
+ /// If provided, will guarentee the update will occur only
+ /// if the value matches the current Status's CommitTag.
+ ///
+ ///
+ /// Thrown if is null.
+ /// Thrown when no matching MachineId was found.
+ /// Thrown when a conflict occured on CommitTag; no update was performed.
+ public async Task> SetMachineStateAsync(
+ string machineId,
+ TState state,
+ Guid? lastCommitTag,
+ CancellationToken cancellationToken = default)
+ {
+ if (machineId == null) throw new ArgumentNullException(nameof(machineId));
+
+ var machineRecord = await DbContext.Machines
+ .SingleOrDefaultAsync(
+ status => status.MachineId == machineId,
+ cancellationToken).ConfigureAwait(false);
+
+ if(machineRecord == null) throw new MachineDoesNotExistException(machineId);
+
+ if (lastCommitTag == null || machineRecord.CommitTag == lastCommitTag)
+ {
+ var stateJson = MessagePackSerializer.ToJson(
+ obj: state,
+ resolver: ContractlessStandardResolver.Instance);
+
+ machineRecord.StateJson = stateJson;
+ machineRecord.CommitTag = Guid.NewGuid();
+ machineRecord.UpdatedTime = DateTimeOffset.UtcNow;
+ }
+ else
+ {
+ throw new StateConflictException();
+ }
+
+ try
+ {
+ await DbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
+ }
+ catch (DbUpdateConcurrencyException ex)
+ {
+ throw new StateConflictException(ex);
+ }
+
+ var schematic = MessagePackSerializer.Deserialize>(
+ bytes: MessagePackSerializer.FromJson(machineRecord.SchematicJson),
+ resolver: ContractlessStandardResolver.Instance);
+
+ IDictionary metadata = null;
+ if(machineRecord.MetadataJson != null)
+ metadata = MessagePackSerializer.Deserialize>(
+ bytes: MessagePackSerializer.FromJson(machineRecord.MetadataJson));
+
+ return new MachineStatus
+ {
+ MachineId = machineId,
+ Schematic = schematic,
+ State = state,
+ Metadata = metadata,
+ CommitTag = machineRecord.CommitTag,
+ UpdatedTime = machineRecord.UpdatedTime
+ };
+ }
+
+ #region IDisposable Support
+ // To detect redundant calls
+ private bool _disposedValue;
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!_disposedValue)
+ {
+ if (disposing)
+ {
+ DbContext.Dispose();
+ }
+
+ _disposedValue = true;
+ }
+ }
+
+ // This code added to correctly implement the disposable pattern.
+ public void Dispose()
+ {
+ // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
+ Dispose(true);
+ }
+ #endregion
+
+ }
+}
diff --git a/src/REstate.Engine.Repositories.EntityFrameworkCore/EntityFrameworkCoreRepositoryComponent.cs b/src/REstate.Engine.Repositories.EntityFrameworkCore/EntityFrameworkCoreRepositoryComponent.cs
new file mode 100644
index 0000000..d68399e
--- /dev/null
+++ b/src/REstate.Engine.Repositories.EntityFrameworkCore/EntityFrameworkCoreRepositoryComponent.cs
@@ -0,0 +1,39 @@
+using System;
+using Microsoft.EntityFrameworkCore;
+using REstate.IoC;
+
+namespace REstate.Engine.Repositories.EntityFrameworkCore
+{
+ ///
+ /// REstate component that configures Entity Framework Core as the state storage system.
+ ///
+ public class EntityFrameworkCoreRepositoryComponent
+ : IComponent
+ {
+ private readonly REstateEntityFrameworkCoreServerOptions _options;
+
+ ///
+ /// Creates an instance of the component given configurationusing a . />
+ ///
+ /// The connection options REstate will use
+ public EntityFrameworkCoreRepositoryComponent(Action optionsBuilder)
+ {
+ var builder = new DbContextOptionsBuilder();
+
+ optionsBuilder?.Invoke(builder);
+
+ _options = new REstateEntityFrameworkCoreServerOptions(builder.Options);
+ }
+
+ ///
+ /// Registers the dependencies of this component and actives necessary configuration
+ ///
+ /// The registrar to which the configuration and dependencies should be added
+ public void Register(IRegistrar registrar)
+ {
+ registrar.Register(_options);
+ registrar.Register(typeof(IRepositoryContextFactory<,>), typeof(EntityFrameworkCoreRepositoryContextFactory<,>));
+ }
+ }
+
+}
diff --git a/src/REstate.Engine.Repositories.EntityFrameworkCore/EntityFrameworkCoreRepositoryContextFactory.cs b/src/REstate.Engine.Repositories.EntityFrameworkCore/EntityFrameworkCoreRepositoryContextFactory.cs
new file mode 100644
index 0000000..664753f
--- /dev/null
+++ b/src/REstate.Engine.Repositories.EntityFrameworkCore/EntityFrameworkCoreRepositoryContextFactory.cs
@@ -0,0 +1,26 @@
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace REstate.Engine.Repositories.EntityFrameworkCore
+{
+
+ public class EntityFrameworkCoreRepositoryContextFactory
+ : IRepositoryContextFactory
+ {
+ internal EntityFrameworkCoreRepositoryContextFactory(REstateEntityFrameworkCoreServerOptions options)
+ {
+ Options = options;
+ }
+
+ private REstateEntityFrameworkCoreServerOptions Options { get; }
+
+ public Task> OpenContextAsync(
+ CancellationToken cancellationToken = default)
+ {
+ return Task.FromResult>(
+ new EntityFrameworkCoreEngineRepositoryContext(
+ new REstateDbContext(Options.DbContextOptions)));
+ }
+ }
+
+}
diff --git a/src/REstate.Engine.Repositories.EntityFrameworkCore/REstate.Engine.Repositories.EntityFrameworkCore.csproj b/src/REstate.Engine.Repositories.EntityFrameworkCore/REstate.Engine.Repositories.EntityFrameworkCore.csproj
new file mode 100644
index 0000000..4691b39
--- /dev/null
+++ b/src/REstate.Engine.Repositories.EntityFrameworkCore/REstate.Engine.Repositories.EntityFrameworkCore.csproj
@@ -0,0 +1,20 @@
+
+
+
+ netstandard2.0
+ latest
+ 2.0.0
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/REstate.Engine.Repositories.EntityFrameworkCore/REstateDbContext.cs b/src/REstate.Engine.Repositories.EntityFrameworkCore/REstateDbContext.cs
new file mode 100644
index 0000000..4c98012
--- /dev/null
+++ b/src/REstate.Engine.Repositories.EntityFrameworkCore/REstateDbContext.cs
@@ -0,0 +1,70 @@
+using System;
+using Microsoft.EntityFrameworkCore;
+
+namespace REstate.Engine.Repositories.EntityFrameworkCore
+{
+ public class EntityFrameworkCoreMachineStatus
+ {
+ public string MachineId { get; set; }
+
+ public Guid CommitTag { get; set; }
+
+ public DateTimeOffset UpdatedTime { get; set; }
+
+ public string StateJson { get; set; }
+
+ public string MetadataJson { get; set; }
+
+ public string SchematicJson { get; set; }
+ }
+
+ public class EntityFrameworkCoreSchematic
+ {
+ public string SchematicName { get; set; }
+
+ public string SchematicJson { get; set; }
+ }
+
+ public class REstateDbContext
+ : DbContext
+ {
+ public REstateDbContext(DbContextOptions options)
+ : base(options)
+ {
+ }
+
+ ///
+ /// Override this method to further configure the model that was discovered by convention from the entity types
+ /// exposed in properties on your derived context. The resulting model may be cached
+ /// and re-used for subsequent instances of your derived context.
+ ///
+ ///
+ /// If a model is explicitly set on the options for this context
+ /// (via )
+ /// then this method will not be run.
+ ///
+ ///
+ /// The builder being used to construct the model for this context. Databases (and other extensions) typically
+ /// define extension methods on this object that allow you to configure aspects of the model that are specific
+ /// to a given database.
+ ///
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ base.OnModelCreating(modelBuilder);
+
+ modelBuilder.Entity()
+ .HasKey(status => status.MachineId);
+
+ modelBuilder.Entity()
+ .Property(status => status.CommitTag)
+ .IsConcurrencyToken();
+
+ modelBuilder.Entity()
+ .HasKey(schematic => schematic.SchematicName);
+ }
+
+ public DbSet Machines { get; set; }
+
+ public DbSet Schematics { get; set; }
+ }
+}
diff --git a/src/REstate.Engine.Repositories.EntityFrameworkCore/REstateEntityFrameworkCoreServerOptions.cs b/src/REstate.Engine.Repositories.EntityFrameworkCore/REstateEntityFrameworkCoreServerOptions.cs
new file mode 100644
index 0000000..dc95162
--- /dev/null
+++ b/src/REstate.Engine.Repositories.EntityFrameworkCore/REstateEntityFrameworkCoreServerOptions.cs
@@ -0,0 +1,15 @@
+using Microsoft.EntityFrameworkCore;
+
+namespace REstate.Engine.Repositories.EntityFrameworkCore
+{
+ internal class REstateEntityFrameworkCoreServerOptions
+ {
+ public REstateEntityFrameworkCoreServerOptions(DbContextOptions dbContextOptions)
+ {
+ DbContextOptions = dbContextOptions;
+ }
+
+ public DbContextOptions DbContextOptions { get; }
+ }
+
+}
diff --git a/src/REstate.Engine.Repositories.Redis/REstate.Engine.Repositories.Redis.csproj b/src/REstate.Engine.Repositories.Redis/REstate.Engine.Repositories.Redis.csproj
index ecec229..278158e 100644
--- a/src/REstate.Engine.Repositories.Redis/REstate.Engine.Repositories.Redis.csproj
+++ b/src/REstate.Engine.Repositories.Redis/REstate.Engine.Repositories.Redis.csproj
@@ -19,7 +19,7 @@
-
+
diff --git a/src/REstate.Remote/GrpcRemoteHostComponent.cs b/src/REstate.Remote/GrpcRemoteHostComponent.cs
index 11d1979..c412112 100644
--- a/src/REstate.Remote/GrpcRemoteHostComponent.cs
+++ b/src/REstate.Remote/GrpcRemoteHostComponent.cs
@@ -1,6 +1,4 @@
using System;
-using Grpc.Core;
-using MagicOnion.Client;
using REstate.Engine;
using REstate.Remote.Services;
using REstate.IoC;
diff --git a/src/REstate.Remote/GrpcStateEngine.cs b/src/REstate.Remote/GrpcStateEngine.cs
index acc6325..f243e72 100644
--- a/src/REstate.Remote/GrpcStateEngine.cs
+++ b/src/REstate.Remote/GrpcStateEngine.cs
@@ -95,17 +95,18 @@ public async Task> CreateMachineAsync(
return new GrpcStateMachine(_stateMachineService, response.MachineId);
}
- public Task BulkCreateMachinesAsync(
+ public Task>> BulkCreateMachinesAsync(
ISchematic schematic,
IEnumerable> metadata,
CancellationToken cancellationToken = default)
=> BulkCreateMachinesAsync(schematic.Clone(), metadata, cancellationToken);
- public async Task BulkCreateMachinesAsync(
+ public async Task>> BulkCreateMachinesAsync(
Schematic schematic,
IEnumerable> metadata,
CancellationToken cancellationToken = default)
- => await _stateMachineService
+ {
+ var response = await _stateMachineService
.WithCancellationToken(cancellationToken)
.BulkCreateMachineFromSchematicAsync(new BulkCreateMachineFromSchematicRequest
{
@@ -113,11 +114,15 @@ public async Task BulkCreateMachinesAsync(
Metadata = metadata
});
- public async Task BulkCreateMachinesAsync(
+ return response.MachineIds.Select(machineId => new GrpcStateMachine(_stateMachineService, machineId));
+ }
+
+ public async Task>> BulkCreateMachinesAsync(
string schematicName,
IEnumerable> metadata,
CancellationToken cancellationToken = default)
- => await _stateMachineService
+ {
+ var response = await _stateMachineService
.WithCancellationToken(cancellationToken)
.BulkCreateMachineFromStoreAsync(new BulkCreateMachineFromStoreRequest
{
@@ -125,6 +130,9 @@ public async Task BulkCreateMachinesAsync(
Metadata = metadata
});
+ return response.MachineIds.Select(machineId => new GrpcStateMachine(_stateMachineService, machineId));
+ }
+
public async Task DeleteMachineAsync(
string machineId,
CancellationToken cancellationToken = default)
diff --git a/src/REstate.Remote/Models/BulkCreateMachine.cs b/src/REstate.Remote/Models/BulkCreateMachine.cs
index 889a951..8e525f1 100644
--- a/src/REstate.Remote/Models/BulkCreateMachine.cs
+++ b/src/REstate.Remote/Models/BulkCreateMachine.cs
@@ -22,4 +22,11 @@ public class BulkCreateMachineFromSchematicRequest
[Key(1)]
public IEnumerable> Metadata { get; set; }
}
+
+ [MessagePackObject]
+ public class BulkCreateMachineResponse
+ {
+ [Key(0)]
+ public IEnumerable MachineIds { get; set; }
+ }
}
\ No newline at end of file
diff --git a/src/REstate.Remote/REstate.Remote.csproj b/src/REstate.Remote/REstate.Remote.csproj
index 3c7dfe7..61c7562 100644
--- a/src/REstate.Remote/REstate.Remote.csproj
+++ b/src/REstate.Remote/REstate.Remote.csproj
@@ -19,9 +19,9 @@
-
+
-
+
diff --git a/src/REstate.Remote/Services/IStateMachineService.cs b/src/REstate.Remote/Services/IStateMachineService.cs
index f320ffb..ea71a3a 100644
--- a/src/REstate.Remote/Services/IStateMachineService.cs
+++ b/src/REstate.Remote/Services/IStateMachineService.cs
@@ -25,8 +25,8 @@ public interface IStateMachineService
UnaryResult CreateMachineFromSchematicAsync(CreateMachineFromSchematicRequest request);
- UnaryResult BulkCreateMachineFromStoreAsync(BulkCreateMachineFromStoreRequest request);
+ UnaryResult BulkCreateMachineFromStoreAsync(BulkCreateMachineFromStoreRequest request);
- UnaryResult BulkCreateMachineFromSchematicAsync(BulkCreateMachineFromSchematicRequest request);
+ UnaryResult BulkCreateMachineFromSchematicAsync(BulkCreateMachineFromSchematicRequest request);
}
}
\ No newline at end of file
diff --git a/src/REstate.Remote/Services/IStateMachineServiceLocalAdapter.cs b/src/REstate.Remote/Services/IStateMachineServiceLocalAdapter.cs
index e9ffadf..c85f623 100644
--- a/src/REstate.Remote/Services/IStateMachineServiceLocalAdapter.cs
+++ b/src/REstate.Remote/Services/IStateMachineServiceLocalAdapter.cs
@@ -9,8 +9,8 @@ namespace REstate.Remote.Services
{
internal interface IStateMachineServiceLocalAdapter
{
- Task BulkCreateMachineFromSchematicAsync(Schematic schematic, IEnumerable> metadata, CancellationToken cancellationToken = default);
- Task BulkCreateMachineFromStoreAsync(string schematicName, IEnumerable> metadata, CancellationToken cancellationToken = default);
+ Task BulkCreateMachineFromSchematicAsync(Schematic schematic, IEnumerable> metadata, CancellationToken cancellationToken = default);
+ Task BulkCreateMachineFromStoreAsync(string schematicName, IEnumerable> metadata, CancellationToken cancellationToken = default);
Task CreateMachineFromSchematicAsync(Schematic schematic, string machineId, IDictionary metadata, CancellationToken cancellationToken = default);
Task CreateMachineFromStoreAsync(string schematicName, string machineId, IDictionary metadata, CancellationToken cancellationToken = default);
Task DeleteMachineAsync(string machineId, CancellationToken cancellationToken);
diff --git a/src/REstate.Remote/Services/StateMachineService.cs b/src/REstate.Remote/Services/StateMachineService.cs
index 541b5a7..78d2dd8 100644
--- a/src/REstate.Remote/Services/StateMachineService.cs
+++ b/src/REstate.Remote/Services/StateMachineService.cs
@@ -25,8 +25,8 @@ namespace REstate.Remote.Services
using GetMachineMetadataAsyncDelegate = Func>;
using CreateMachineFromStoreAsyncDelegate = Func, CancellationToken, Task>;
using CreateMachineFromSchematicAsyncDelegate = Func