diff options
author | rtk0c <[email protected]> | 2021-04-14 15:09:13 -0700 |
---|---|---|
committer | rtk0c <[email protected]> | 2021-04-14 15:09:13 -0700 |
commit | 80d8ae5a6fef6c9a34e81e240539cb655dd99851 (patch) | |
tree | 062bb1590eaf030b75aae75acecc5706e16d9b0c /core/src/Model | |
parent | 568fcc1dfe40c37b57b7baa2dea93b291d3fa956 (diff) |
Initial work on workflows
Diffstat (limited to 'core/src/Model')
-rw-r--r-- | core/src/Model/EvaluatedValue.cpp | 49 | ||||
-rw-r--r-- | core/src/Model/EvaluatedValue.hpp | 64 | ||||
-rw-r--r-- | core/src/Model/Workflow.cpp | 98 | ||||
-rw-r--r-- | core/src/Model/Workflow.hpp | 101 | ||||
-rw-r--r-- | core/src/Model/WorkflowSteps.cpp | 11 | ||||
-rw-r--r-- | core/src/Model/WorkflowSteps.hpp | 44 | ||||
-rw-r--r-- | core/src/Model/fwd.hpp | 20 |
7 files changed, 387 insertions, 0 deletions
diff --git a/core/src/Model/EvaluatedValue.cpp b/core/src/Model/EvaluatedValue.cpp new file mode 100644 index 0000000..c86f00b --- /dev/null +++ b/core/src/Model/EvaluatedValue.cpp @@ -0,0 +1,49 @@ +#include "EvaluatedValue.hpp" + +BaseValue::BaseValue(Type type) + : mType{ type } { +} + +BaseValue::Type BaseValue::GetType() const { + return mType; +} + +NumericValue::NumericValue() + : BaseValue(BaseValue::NumericType) { +} + +int64_t NumericValue::GetInt() const { + return static_cast<int64_t>(mValue); +} + +double NumericValue::GetValue() const { + return mValue; +} + +void NumericValue::SetValue(double value) { + mValue = value; +} + +TextValue::TextValue() + : BaseValue(BaseValue::TextType) { +} + +const std::string& TextValue::GetValue() const { + return mValue; +} + +void TextValue::SetValue(const std::string& value) { + mValue = value; +} + +DateTimeValue::DateTimeValue() + : BaseValue(BaseValue::DateTimeType) { +} + +const std::chrono::time_point<std::chrono::system_clock>& DateTimeValue::GetValue() const { + return mValue; +} + +void DateTimeValue::SetValue(const std::chrono::time_point<std::chrono::system_clock>& value) { + mValue = value; +} diff --git a/core/src/Model/EvaluatedValue.hpp b/core/src/Model/EvaluatedValue.hpp new file mode 100644 index 0000000..838fc39 --- /dev/null +++ b/core/src/Model/EvaluatedValue.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include <chrono> +#include <cstdint> +#include <string> + +class BaseValue { +public: + enum Type { + NumericType, + TextType, + DateTimeType, + + /// An unspecified type, otherwise known as "any" in some contexts. + InvalidType, + TypeCount = InvalidType, + }; + +private: + Type mType; + +public: + BaseValue(Type type); + virtual ~BaseValue() = default; + + BaseValue(const BaseValue&) = delete; + BaseValue& operator=(const BaseValue&) = delete; + BaseValue(BaseValue&&) = default; + BaseValue& operator=(BaseValue&&) = default; + + Type GetType() const; +}; + +class NumericValue : public BaseValue { +private: + double mValue; + +public: + NumericValue(); + + int64_t GetInt() const; + double GetValue() const; + void SetValue(double value); +}; + +class TextValue : public BaseValue { +private: + std::string mValue; + +public: + TextValue(); + const std::string& GetValue() const; + void SetValue(const std::string& value); +}; + +class DateTimeValue : public BaseValue { +private: + std::chrono::time_point<std::chrono::system_clock> mValue; + +public: + DateTimeValue(); + const std::chrono::time_point<std::chrono::system_clock>& GetValue() const; + void SetValue(const std::chrono::time_point<std::chrono::system_clock>& value); +}; diff --git a/core/src/Model/Workflow.cpp b/core/src/Model/Workflow.cpp new file mode 100644 index 0000000..96031c1 --- /dev/null +++ b/core/src/Model/Workflow.cpp @@ -0,0 +1,98 @@ +#include "Workflow.hpp" + +bool WorkflowStep::InputNode::IsConnected() const { + return ConnectedNodeIndex != -1; +} + +bool WorkflowStep::OutputNode::IsConnected() const { + return ConnectedNodeIndex != -1; +} + +size_t WorkflowStep::GetId() const { + return mId; +} + +void WorkflowStep::ConnectInput(int nodeId, size_t outputId, int outputNodeId) { + mWorkflow->Connect(mId, nodeId, outputId, outputNodeId); +} + +void WorkflowStep::DisconnectInput(int nodeId) { + mWorkflow->DisconnectByDestination(mId, nodeId); +} + +bool WorkflowStep::IsInputConnected(int nodeId) const { + return mInputs[nodeId].IsConnected(); +} + +void WorkflowStep::ConnectOutput(int nodeId, size_t inputId, int inputNodeId) { + mWorkflow->Connect(inputId, inputNodeId, mId, nodeId); +} + +void WorkflowStep::DisconnectOutput(int nodeId) { + mWorkflow->DisconnectBySource(mId, nodeId); +} + +bool WorkflowStep::IsOutputConnected(int nodeId) const { + return mOutputs[nodeId].IsConnected(); +} + +WorkflowConnection* Workflow::GetConnectionById(size_t id) { + return &mConnections[id]; +} + +WorkflowStep* Workflow::GetStepById(size_t id) { + return mSteps[id].get(); +} + +void WorkflowStep::OnIOAboutToChange() { + // TODO more robust solution that handles changes incrementally + for (size_t i = 0; i < mInputs.size(); ++i) { + DisconnectInput(i); + } + for (size_t i = 0; i < mOutputs.size(); ++i) { + DisconnectOutput(i); + } +} + +void WorkflowStep::OnIOChanged() { +} + +void Workflow::Connect(size_t source, int sourceNode, size_t destination, int destinationNode) { + auto& src = *mSteps[source]; + auto& o = src.mInputs[sourceNode]; + if (o.IsConnected()) { + DisconnectBySource(source, sourceNode); + } + + o.ConnectedStep = destination; + o.ConnectedNodeIndex = destinationNode; + + auto& dst = *mSteps[destination]; + auto& i = dst.mInputs[destinationNode]; + i.ConnectedStep = source; + i.ConnectedNodeIndex = sourceNode; +} + +void Workflow::DisconnectBySource(size_t source, int sourceNode) { + auto& src = *mSteps[source]; + auto& o = src.mOutputs[sourceNode]; + if (!o.IsConnected()) return; + + auto& i = mSteps[o.ConnectedStep]->mInputs[o.ConnectedNodeIndex]; + i.ConnectedStep = WorkflowStep::kInvalidId; + i.ConnectedNodeIndex = -1; + o.ConnectedStep = WorkflowStep::kInvalidId; + o.ConnectedNodeIndex = -1; +} + +void Workflow::DisconnectByDestination(size_t destination, int destinationNode) { + auto& dst = *mSteps[destination]; + auto& i = dst.mInputs[destinationNode]; + if (!i.IsConnected()) return; + + auto& o = mSteps[i.ConnectedStep]->mOutputs[i.ConnectedNodeIndex]; + i.ConnectedStep = WorkflowStep::kInvalidId; + i.ConnectedNodeIndex = -1; + o.ConnectedStep = WorkflowStep::kInvalidId; + o.ConnectedNodeIndex = -1; +} diff --git a/core/src/Model/Workflow.hpp b/core/src/Model/Workflow.hpp new file mode 100644 index 0000000..a90ef21 --- /dev/null +++ b/core/src/Model/Workflow.hpp @@ -0,0 +1,101 @@ +#pragma once + +#include "EvaluatedValue.hpp" + +#include <cstddef> +#include <cstdint> +#include <limits> +#include <memory> +#include <vector> + +class WorkflowConnection { +public: + size_t Source; + size_t Destination; +}; + +class WorkflowStep { +public: + static constexpr auto kInvalidId = std::numeric_limits<size_t>::max(); + + // TODO do we even need this? + // enum Type { + // NumericAdditionType, + // NumericSubtractionType, + // NumericMultiplicationType, + // NumericDivisionType, + // NumericExpressionType, + // TextFormattingType, + // FormInputType, + // DatabaseRowsInputType, + // DocumentTemplateExpansionType, + // + // InvalidType, + // TypeCount = InvalidType, + // }; + +protected: + struct InputNode { + size_t ConnectedStep = kInvalidId; + int ConnectedNodeIndex = -1; + BaseValue::Type MatchingType = BaseValue::InvalidType; + + bool IsConnected() const; + }; + + struct OutputNode { + size_t ConnectedStep = kInvalidId; + int ConnectedNodeIndex = -1; + BaseValue::Type MatchingType = BaseValue::InvalidType; + + bool IsConnected() const; + }; + + friend class Workflow; + Workflow* mWorkflow; + size_t mId; + std::vector<InputNode> mInputs; + std::vector<OutputNode> mOutputs; + +public: + virtual ~WorkflowStep() = default; + + WorkflowStep(const WorkflowStep&) = delete; + WorkflowStep& operator=(const WorkflowStep&) = delete; + WorkflowStep(WorkflowStep&&) = default; + WorkflowStep& operator=(WorkflowStep&&) = default; + + size_t GetId() const; + + void ConnectInput(int nodeId, size_t outputId, int outputNodeId); + void DisconnectInput(int nodeId); + bool IsInputConnected(int nodeId) const; + + void ConnectOutput(int nodeId, size_t inputId, int inputNodeId); + void DisconnectOutput(int nodeId); + bool IsOutputConnected(int nodeId) const; + +protected: + /// Child classes should call this whenever \c mInputs and \c mOutputs are about to be modified (append or remove) + /// after invocation of the constructor. + void OnIOAboutToChange(); + void OnIOChanged(); +}; + +class Workflow { +private: + std::vector<WorkflowConnection> mConnections; + std::vector<std::unique_ptr<WorkflowStep>> mSteps; + +public: + WorkflowConnection* GetConnectionById(size_t id); + WorkflowStep* GetStepById(size_t id); + + void Connect(size_t source, int sourceNode, size_t destination, int destinationNode); + void DisconnectBySource(size_t source, int sourceNode); + void DisconnectByDestination(size_t destination, int destinationNode); +}; + +class WorkflowEvaluationContext { + +}; diff --git a/core/src/Model/WorkflowSteps.cpp b/core/src/Model/WorkflowSteps.cpp new file mode 100644 index 0000000..815c5ca --- /dev/null +++ b/core/src/Model/WorkflowSteps.cpp @@ -0,0 +1,11 @@ +#include "WorkflowSteps.hpp" + +NumericOperationStep::NumericOperationStep(NumericOperationStep::Type type) + : mType{ type } { + mInputs.resize(2); + mInputs[0].MatchingType = BaseValue::NumericType; + mInputs[1].MatchingType = BaseValue::NumericType; + + mOutputs.resize(1); + mOutputs[0].MatchingType = BaseValue::NumericType; +} diff --git a/core/src/Model/WorkflowSteps.hpp b/core/src/Model/WorkflowSteps.hpp new file mode 100644 index 0000000..819ca63 --- /dev/null +++ b/core/src/Model/WorkflowSteps.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include "Model/Workflow.hpp" + +#include <memory> + +class NumericOperationStep : public WorkflowStep { +public: + enum Type { + Addition, + Subtraction, + Multiplication, + Division, + + InvalidType, + TypeCount = InvalidType, + }; + +private: + Type mType; + +public: + NumericOperationStep(Type type); +}; + +class NumericExpressionStep : public WorkflowStep { +public: +}; + +class FormatTextStep : public WorkflowStep { +public: +}; + +class FormInputStep : public WorkflowStep { +public: +}; + +class DatabaseRowsInputStep : public WorkflowStep { +public: +}; + +class DocumentTemplateExpansionStep : public WorkflowStep { +public: +}; diff --git a/core/src/Model/fwd.hpp b/core/src/Model/fwd.hpp index 4bd508c..a2156aa 100644 --- a/core/src/Model/fwd.hpp +++ b/core/src/Model/fwd.hpp @@ -1,5 +1,11 @@ #pragma once +// EvaluatedValue.hpp +class BaseValue; +class NumericValue; +class TextValue; +class DateTimeValue; + // Filter.hpp class TableRowsFilter; @@ -23,3 +29,17 @@ class SalesTable; class PurchasesTable; class DeliveryTable; class TransactionModel; + +// Workflow.hpp +class WorkflowConnection; +class WorkflowStep; +class Workflow; +class WorkflowEvaluationContext; + +// WorkflowSteps.hpp +class NumericOperationStep; +class NumericExpressionStep; +class FormatTextStep; +class FormInputStep; +class DatabaseRowsInputStep; +class DocumentTemplateExpansionStep; |