summaryrefslogtreecommitdiff
path: root/core/src/Model
diff options
context:
space:
mode:
authorrtk0c <[email protected]>2021-04-14 15:09:13 -0700
committerrtk0c <[email protected]>2021-04-14 15:09:13 -0700
commit80d8ae5a6fef6c9a34e81e240539cb655dd99851 (patch)
tree062bb1590eaf030b75aae75acecc5706e16d9b0c /core/src/Model
parent568fcc1dfe40c37b57b7baa2dea93b291d3fa956 (diff)
Initial work on workflows
Diffstat (limited to 'core/src/Model')
-rw-r--r--core/src/Model/EvaluatedValue.cpp49
-rw-r--r--core/src/Model/EvaluatedValue.hpp64
-rw-r--r--core/src/Model/Workflow.cpp98
-rw-r--r--core/src/Model/Workflow.hpp101
-rw-r--r--core/src/Model/WorkflowSteps.cpp11
-rw-r--r--core/src/Model/WorkflowSteps.hpp44
-rw-r--r--core/src/Model/fwd.hpp20
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;