diff --git a/src/ServerlessWorkflow.Sdk.IO/Extensions/IServiceCollectionExtensions.cs b/src/ServerlessWorkflow.Sdk.IO/Extensions/IServiceCollectionExtensions.cs index 2c1bc6c..770b109 100644 --- a/src/ServerlessWorkflow.Sdk.IO/Extensions/IServiceCollectionExtensions.cs +++ b/src/ServerlessWorkflow.Sdk.IO/Extensions/IServiceCollectionExtensions.cs @@ -39,7 +39,9 @@ public static IServiceCollection AddServerlessWorkflowIO(this IServiceCollection options.Deserializer.WithNodeDeserializer( inner => new TaskDefinitionYamlDeserializer(inner), syntax => syntax.InsteadOf()); - options.Serializer.WithTypeConverter(new MapEntryYamlConverter(() => options.Serializer.Build())); + var mapEntryConverter = new MapEntryYamlConverter(() => options.Serializer.Build(), () => options.Deserializer.Build()); + options.Deserializer.WithTypeConverter(mapEntryConverter); + options.Serializer.WithTypeConverter(mapEntryConverter); }); services.AddSingleton(); services.AddSingleton(); diff --git a/src/ServerlessWorkflow.Sdk/Models/DataModelDefinition.cs b/src/ServerlessWorkflow.Sdk/Models/ContextDataModelDefinition.cs similarity index 71% rename from src/ServerlessWorkflow.Sdk/Models/DataModelDefinition.cs rename to src/ServerlessWorkflow.Sdk/Models/ContextDataModelDefinition.cs index c80c286..274a53c 100644 --- a/src/ServerlessWorkflow.Sdk/Models/DataModelDefinition.cs +++ b/src/ServerlessWorkflow.Sdk/Models/ContextDataModelDefinition.cs @@ -14,22 +14,22 @@ namespace ServerlessWorkflow.Sdk.Models; /// -/// Represents the definition of a data model +/// Represents the definition of a data context /// [DataContract] -public abstract record DataModelDefinition +public record ContextDataModelDefinition { /// - /// Gets/sets the schema, if any, that defines and describes the defined data model + /// Gets/sets the schema, if any, that defines and describes the context data /// [DataMember(Name = "schema", Order = 1), JsonPropertyName("schema"), JsonPropertyOrder(1), YamlMember(Alias = "schema", Order = 1)] public virtual SchemaDefinition? Schema { get; set; } /// - /// Gets/sets a runtime expression, if any, used to build the defined model using both input and scope data + /// Gets/sets a runtime expression, if any, used to export specific data to the context data /// - [DataMember(Name = "from", Order = 2), JsonPropertyName("from"), JsonPropertyOrder(2), JsonInclude, YamlMember(Alias = "from", Order = 2)] - public virtual object? From { get; set; } + [DataMember(Name = "as", Order = 3), JsonPropertyName("as"), JsonPropertyOrder(3), YamlMember(Alias = "as", Order = 3)] + public virtual object? As { get; set; } -} +} \ No newline at end of file diff --git a/src/ServerlessWorkflow.Sdk/Models/InputDataModelDefinition.cs b/src/ServerlessWorkflow.Sdk/Models/InputDataModelDefinition.cs index d2026e9..270bdde 100644 --- a/src/ServerlessWorkflow.Sdk/Models/InputDataModelDefinition.cs +++ b/src/ServerlessWorkflow.Sdk/Models/InputDataModelDefinition.cs @@ -14,13 +14,22 @@ namespace ServerlessWorkflow.Sdk.Models; /// -/// Represents the definition of an output data model +/// Represents the definition of an input data model /// [DataContract] public record InputDataModelDefinition - : DataModelDefinition { + /// + /// Gets/sets the schema, if any, that defines and describes the input data of a workflow or task + /// + [DataMember(Name = "schema", Order = 1), JsonPropertyName("schema"), JsonPropertyOrder(1), YamlMember(Alias = "schema", Order = 1)] + public virtual SchemaDefinition? Schema { get; set; } + /// + /// Gets/sets a runtime expression, if any, used to build the workflow or task input data based on both input and scope data + /// + [DataMember(Name = "from", Order = 2), JsonPropertyName("from"), JsonPropertyOrder(2), JsonInclude, YamlMember(Alias = "from", Order = 2)] + public virtual object? From { get; set; } } diff --git a/src/ServerlessWorkflow.Sdk/Models/OutputDataModelDefinition.cs b/src/ServerlessWorkflow.Sdk/Models/OutputDataModelDefinition.cs index 35520fd..63f16ce 100644 --- a/src/ServerlessWorkflow.Sdk/Models/OutputDataModelDefinition.cs +++ b/src/ServerlessWorkflow.Sdk/Models/OutputDataModelDefinition.cs @@ -18,13 +18,18 @@ namespace ServerlessWorkflow.Sdk.Models; /// [DataContract] public record OutputDataModelDefinition - : DataModelDefinition { + /// + /// Gets/sets the schema, if any, that defines and describes the output data of a workflow or task + /// + [DataMember(Name = "schema", Order = 1), JsonPropertyName("schema"), JsonPropertyOrder(1), YamlMember(Alias = "schema", Order = 1)] + public virtual SchemaDefinition? Schema { get; set; } + /// /// Gets/sets a runtime expression, if any, used to output specific data to the scope data /// - [DataMember(Name = "to", Order = 3), JsonPropertyName("to"), JsonPropertyOrder(3), YamlMember(Alias = "to", Order = 3)] - public virtual object? To { get; set; } + [DataMember(Name = "as", Order = 3), JsonPropertyName("as"), JsonPropertyOrder(3), YamlMember(Alias = "as", Order = 3)] + public virtual object? As { get; set; } -} \ No newline at end of file +} diff --git a/src/ServerlessWorkflow.Sdk/Models/TaskDefinition.cs b/src/ServerlessWorkflow.Sdk/Models/TaskDefinition.cs index 8facecf..91f49fc 100644 --- a/src/ServerlessWorkflow.Sdk/Models/TaskDefinition.cs +++ b/src/ServerlessWorkflow.Sdk/Models/TaskDefinition.cs @@ -12,7 +12,6 @@ // limitations under the License. using ServerlessWorkflow.Sdk.Serialization.Json; -using System.ComponentModel; namespace ServerlessWorkflow.Sdk.Models; @@ -42,16 +41,22 @@ public abstract record TaskDefinition [DataMember(Name = "output", Order = 11), JsonPropertyName("output"), JsonPropertyOrder(11), YamlMember(Alias = "output", Order = 11)] public virtual OutputDataModelDefinition? Output { get; set; } + /// + /// Gets/sets the optional configuration for exporting data within the task's context + /// + [DataMember(Name = "export", Order = 12), JsonPropertyName("export"), JsonPropertyOrder(12), YamlMember(Alias = "export", Order = 12)] + public virtual OutputDataModelDefinition? Export { get; set; } + /// /// Gets/sets a boolean indicating whether or not to return the result, if any, of the defined task /// - [DataMember(Name = "timeout", Order = 12), JsonPropertyName("timeout"), JsonPropertyOrder(12), YamlMember(Alias = "timeout", Order = 12)] + [DataMember(Name = "timeout", Order = 13), JsonPropertyName("timeout"), JsonPropertyOrder(13), YamlMember(Alias = "timeout", Order = 13)] public virtual TimeoutDefinition? Timeout { get; set; } /// /// Gets/sets the flow directive to be performed upon completion of the task /// - [DataMember(Name = "then", Order = 13), JsonPropertyName("then"), JsonPropertyOrder(13), YamlMember(Alias = "then", Order = 13)] + [DataMember(Name = "then", Order = 14), JsonPropertyName("then"), JsonPropertyOrder(14), YamlMember(Alias = "then", Order = 14)] public virtual string? Then { get; set; } } diff --git a/src/ServerlessWorkflow.Sdk/Serialization/Yaml/MapEntryYamlConverter.cs b/src/ServerlessWorkflow.Sdk/Serialization/Yaml/MapEntryYamlConverter.cs index f030920..713b932 100644 --- a/src/ServerlessWorkflow.Sdk/Serialization/Yaml/MapEntryYamlConverter.cs +++ b/src/ServerlessWorkflow.Sdk/Serialization/Yaml/MapEntryYamlConverter.cs @@ -21,7 +21,8 @@ namespace ServerlessWorkflow.Sdk.Serialization.Yaml; /// Represents the service used to serialize/deserialize values to/from YAML /// /// A function used to create a new -public class MapEntryYamlConverter(Func serializerFactory) +/// A function used to create a new +public class MapEntryYamlConverter(Func serializerFactory, Func deserializerFactory) : IYamlTypeConverter { @@ -43,10 +44,10 @@ protected virtual IYamlTypeConverter CreateGenericConverter(Type type) { var typeArguments = type.GetGenericArguments(); var converterType = typeof(MapEntryConverter<,>).MakeGenericType(typeArguments); - return (IYamlTypeConverter)Activator.CreateInstance(converterType, serializerFactory())!; + return (IYamlTypeConverter)Activator.CreateInstance(converterType, serializerFactory(), deserializerFactory())!; } - class MapEntryConverter (ISerializer serializer) + class MapEntryConverter (ISerializer serializer, IDeserializer deserializer) : IYamlTypeConverter where TKey : notnull { @@ -55,7 +56,14 @@ class MapEntryConverter (ISerializer serializer) public bool Accepts(Type type) => type == typeof(MapEntry); /// - public virtual object ReadYaml(IParser parser, Type type) => throw new NotImplementedException(); + public virtual object ReadYaml(IParser parser, Type type) + { + parser.Consume(); + var key = deserializer.Deserialize(parser); + var value = deserializer.Deserialize(parser); + parser.Consume(); + return new MapEntry(key, value); + } /// public virtual void WriteYaml(IEmitter emitter, object? value, Type type) diff --git a/tests/ServerlessWorkflow.Sdk.UnitTests/Cases/IO/WorkflowDefinitionWriterTests.cs b/tests/ServerlessWorkflow.Sdk.UnitTests/Cases/IO/WorkflowDefinitionIOTests.cs similarity index 89% rename from tests/ServerlessWorkflow.Sdk.UnitTests/Cases/IO/WorkflowDefinitionWriterTests.cs rename to tests/ServerlessWorkflow.Sdk.UnitTests/Cases/IO/WorkflowDefinitionIOTests.cs index d729f14..2995e5c 100644 --- a/tests/ServerlessWorkflow.Sdk.UnitTests/Cases/IO/WorkflowDefinitionWriterTests.cs +++ b/tests/ServerlessWorkflow.Sdk.UnitTests/Cases/IO/WorkflowDefinitionIOTests.cs @@ -15,11 +15,11 @@ namespace ServerlessWorkflow.Sdk.UnitTests.Cases.IO; -public class WorkflowDefinitionWriterTests +public class WorkflowDefinitionIOTests { [Fact] - public async Task Write_Workflow_Definition_To_Yaml_Should_Work() + public async Task WriteThenRead_Workflow_Definition_ToFrom_Yaml_Should_Work() { //arrange var toSerialize = WorkflowDefinitionFactory.Create(); @@ -32,6 +32,7 @@ public async Task Write_Workflow_Definition_To_Yaml_Should_Work() await stream.FlushAsync(); stream.Position = 0; var yaml = new StreamReader(stream).ReadToEnd(); + stream.Position = 0; var deserialized = await reader.ReadAsync(stream); //assert @@ -40,7 +41,7 @@ public async Task Write_Workflow_Definition_To_Yaml_Should_Work() } [Fact] - public async Task Write_Workflow_Definition_To_Json_Should_Work() + public async Task WriteThenRead_Workflow_Definition_ToFrom_Json_Should_Work() { //arrange var toSerialize = WorkflowDefinitionFactory.Create(); diff --git a/tests/ServerlessWorkflow.Sdk.UnitTests/Cases/IO/WorkflowDefinitionReaderTests.cs b/tests/ServerlessWorkflow.Sdk.UnitTests/Cases/IO/WorkflowDefinitionReaderTests.cs deleted file mode 100644 index d1772fe..0000000 --- a/tests/ServerlessWorkflow.Sdk.UnitTests/Cases/IO/WorkflowDefinitionReaderTests.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright © 2024-Present The Serverless Workflow Specification Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"), -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -using ServerlessWorkflow.Sdk.IO; -using Neuroglia.Serialization.Json; -using Neuroglia.Serialization.Yaml; - -namespace ServerlessWorkflow.Sdk.UnitTests.Cases.IO; - -public class WorkflowDefinitionReaderTests -{ - - [Fact] - public async Task Read_Workflow_Definition_From_Json_Should_Work() - { - //arrange - var toSerialize = WorkflowDefinitionFactory.Create(); - using var stream = new MemoryStream(); - JsonSerializer.Default.Serialize(toSerialize, stream); - await stream.FlushAsync(); - stream.Position = 0; - var reader = WorkflowDefinitionReader.Create(); - - //act - var deserialized = await reader.ReadAsync(stream); - - //assert - deserialized.Should().NotBeNull(); - deserialized.Should().BeEquivalentTo(toSerialize); - } - - [Fact] - public async Task Read_Workflow_Definition_From_Yaml_Should_Work() - { - //arrange - var toSerialize = WorkflowDefinitionFactory.Create(); - using var stream = new MemoryStream(); - YamlSerializer.Default.Serialize(toSerialize, stream); - await stream.FlushAsync(); - stream.Position = 0; - var reader = WorkflowDefinitionReader.Create(); - - //act - var deserialized = await reader.ReadAsync(stream); - - //assert - deserialized.Should().NotBeNull(); - deserialized.Should().BeEquivalentTo(toSerialize); - } - -} -