Skip to content

Commit e7162c8

Browse files
committed
Generalize workflow system.
1 parent a369469 commit e7162c8

File tree

15 files changed

+735
-121
lines changed

15 files changed

+735
-121
lines changed

integration_test/scenario_flow_test.go

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515

1616
"github.com/checkmarble/marble-backend/models"
1717
"github.com/checkmarble/marble-backend/models/ast"
18-
"github.com/checkmarble/marble-backend/pure_utils"
1918
"github.com/checkmarble/marble-backend/usecases"
2019
"github.com/checkmarble/marble-backend/usecases/payload_parser"
2120
"github.com/checkmarble/marble-backend/usecases/scenarios"
@@ -407,15 +406,30 @@ func setupScenarioAndPublish(
407406
}
408407
fmt.Printf("Updated scenario iteration %+v\n", scenarioIteration)
409408

410-
workflowType := models.WorkflowAddToCaseIfPossible
411-
_, err = scenarioUsecase.UpdateScenario(ctx, models.UpdateScenarioInput{
412-
Id: scenarioId,
413-
DecisionToCaseOutcomes: []models.Outcome{models.Decline, models.Review},
414-
DecisionToCaseInboxId: pure_utils.NullFrom(inboxId),
415-
DecisionToCaseWorkflowType: &workflowType,
409+
rule, err := scenarioUsecase.CreateWorkflowRule(ctx, organizationId, models.WorkflowRule{
410+
ScenarioId: scenarioId,
411+
Name: "First rule",
416412
})
417413
if err != nil {
418-
assert.FailNow(t, "Failed to create workflow on scenario", err)
414+
assert.FailNow(t, "Could not create workflow rule", err)
415+
}
416+
417+
_, err = scenarioUsecase.CreateWorkflowCondition(ctx, organizationId, models.WorkflowCondition{
418+
RuleId: rule.Id,
419+
Function: "if_outcome_in",
420+
Params: []byte(`["decline", "review"]`),
421+
})
422+
if err != nil {
423+
assert.FailNow(t, "Could not create workflow condition", err)
424+
}
425+
426+
_, err = scenarioUsecase.CreateWorkflowAction(ctx, organizationId, models.WorkflowAction{
427+
RuleId: rule.Id,
428+
Action: models.WorkflowAddToCaseIfPossible,
429+
Params: fmt.Appendf(nil, `{"inbox_id": "%s"}`, inboxId),
430+
})
431+
if err != nil {
432+
assert.FailNow(t, "Could not create workflow action", err)
419433
}
420434

421435
return scenarioId, scenarioIterationId

models/scenarios.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@ var ValidWorkflowTypes = []WorkflowType{
2222
WorkflowAddToCaseIfPossible,
2323
}
2424

25+
func WorkflowTypeFromString(s string) WorkflowType {
26+
switch s {
27+
case "ADD_TO_CASE_IF_POSSIBLE":
28+
return WorkflowAddToCaseIfPossible
29+
case "CREATE_CASE":
30+
return WorkflowCreateCase
31+
default:
32+
return WorkflowDisabled
33+
}
34+
}
35+
2536
type Scenario struct {
2637
Id string
2738
CreatedAt time.Time

models/workflows.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package models
2+
3+
import (
4+
"encoding/json"
5+
"time"
6+
7+
"github.com/checkmarble/marble-backend/models/ast"
8+
"github.com/google/uuid"
9+
)
10+
11+
type WorkflowRule struct {
12+
Id string
13+
ScenarioId string
14+
Name string
15+
Priority int
16+
17+
CreatedAt time.Time
18+
UpdatedAt *time.Time
19+
}
20+
21+
type WorkflowCondition struct {
22+
Id string
23+
RuleId string
24+
Function string
25+
Params json.RawMessage
26+
27+
CreatedAt time.Time
28+
UpdatedAt *time.Time
29+
}
30+
31+
type WorkflowAction struct {
32+
Id string
33+
RuleId string
34+
Action WorkflowType
35+
Params json.RawMessage
36+
37+
CreatedAt time.Time
38+
UpdatedAt *time.Time
39+
}
40+
41+
type WorkflowRuleWithConditions struct {
42+
WorkflowRule
43+
44+
Conditions []WorkflowCondition
45+
Actions []WorkflowAction
46+
}
47+
48+
type WorkflowActionSpec[T any] struct {
49+
Action WorkflowType
50+
Params T
51+
}
52+
53+
type WorkflowCaseParams struct {
54+
InboxId *uuid.UUID `json:"inbox_id"`
55+
TitleTemplate *ast.Node `json:"title_template"`
56+
}
57+
58+
type WorkflowExecution struct {
59+
AddedToCase bool
60+
WebhookIds []string
61+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package dbmodels
2+
3+
import (
4+
"encoding/json"
5+
"time"
6+
7+
"github.com/checkmarble/marble-backend/models"
8+
"github.com/checkmarble/marble-backend/pure_utils"
9+
"github.com/checkmarble/marble-backend/utils"
10+
)
11+
12+
type DbWorkflowRule struct {
13+
Id string `db:"id"`
14+
ScenarioId string `db:"scenario_id"`
15+
Name string `db:"name"`
16+
Priority int `db:"priority"`
17+
18+
CreatedAt time.Time `db:"created_at"`
19+
UpdatedAt *time.Time `db:"updated_at"`
20+
}
21+
22+
type DbWorkflowRuleWithConditions struct {
23+
DbWorkflowRule
24+
25+
Conditions []DbWorkflowCondition `db:"conditions"`
26+
Actions []DbWorkflowAction `db:"actions"`
27+
}
28+
29+
type DbWorkflowCondition struct {
30+
Id string `db:"id"`
31+
RuleId string `db:"rule_id"`
32+
Function string `db:"function"`
33+
Params json.RawMessage `db:"params"`
34+
35+
CreatedAt time.Time `db:"created_at"`
36+
UpdatedAt *time.Time `db:"updated_at"`
37+
}
38+
39+
type DbWorkflowAction struct {
40+
Id string `db:"id"`
41+
RuleId string `db:"rule_id"`
42+
Action string `db:"action"`
43+
Params json.RawMessage `db:"params"`
44+
45+
CreatedAt time.Time `db:"created_at"`
46+
UpdatedAt *time.Time `db:"updated_at"`
47+
}
48+
49+
const TABLE_WORKFLOW_RULES = "scenario_workflow_rules"
50+
const TABLE_WORKFLOW_CONDITIONS = "scenario_workflow_conditions"
51+
const TABLE_WORKFLOW_ACTIONS = "scenario_workflow_actions"
52+
53+
var WorkflowRuleColumns = utils.ColumnList[DbWorkflowRule]()
54+
var WorkflowConditionColumns = utils.ColumnList[DbWorkflowCondition]()
55+
var WorkflowActionColumns = utils.ColumnList[DbWorkflowAction]()
56+
57+
func AdaptWorkflowRule(db DbWorkflowRule) (models.WorkflowRule, error) {
58+
return models.WorkflowRule{
59+
Id: db.Id,
60+
ScenarioId: db.ScenarioId,
61+
Priority: db.Priority,
62+
CreatedAt: db.CreatedAt,
63+
UpdatedAt: db.UpdatedAt,
64+
}, nil
65+
}
66+
67+
func AdaptWorkflowCondition(db DbWorkflowCondition) (models.WorkflowCondition, error) {
68+
return models.WorkflowCondition{
69+
Id: db.Id,
70+
RuleId: db.RuleId,
71+
Function: db.Function,
72+
Params: db.Params,
73+
CreatedAt: db.CreatedAt,
74+
UpdatedAt: db.UpdatedAt,
75+
}, nil
76+
}
77+
78+
func AdaptWorkflowAction(db DbWorkflowAction) (models.WorkflowAction, error) {
79+
return models.WorkflowAction{
80+
Id: db.Id,
81+
RuleId: db.RuleId,
82+
Action: models.WorkflowTypeFromString(db.Action),
83+
Params: db.Params,
84+
CreatedAt: db.CreatedAt,
85+
UpdatedAt: db.UpdatedAt,
86+
}, nil
87+
}
88+
89+
func AdaptWorkflowRuleWithConditions(db DbWorkflowRuleWithConditions) (models.WorkflowRuleWithConditions, error) {
90+
rule, err := AdaptWorkflowRule(db.DbWorkflowRule)
91+
if err != nil {
92+
return models.WorkflowRuleWithConditions{}, err
93+
}
94+
95+
conditions, err := pure_utils.MapErr(db.Conditions, AdaptWorkflowCondition)
96+
if err != nil {
97+
return models.WorkflowRuleWithConditions{}, err
98+
}
99+
100+
actions, err := pure_utils.MapErr(db.Actions, AdaptWorkflowAction)
101+
if err != nil {
102+
return models.WorkflowRuleWithConditions{}, err
103+
}
104+
105+
return models.WorkflowRuleWithConditions{
106+
WorkflowRule: rule,
107+
Conditions: conditions,
108+
Actions: actions,
109+
}, nil
110+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
-- +goose Up
2+
3+
create table scenario_workflow_rules (
4+
id uuid primary key default gen_random_uuid(),
5+
scenario_id uuid not null,
6+
name text not null,
7+
priority int,
8+
created_at timestamp with time zone default now(),
9+
updated_at timestamp with time zone,
10+
11+
constraint fk_scenario
12+
foreign key (scenario_id) references scenarios (id)
13+
on delete cascade
14+
);
15+
16+
create table scenario_workflow_conditions (
17+
id uuid primary key default gen_random_uuid(),
18+
rule_id uuid not null,
19+
function text not null,
20+
params jsonb,
21+
created_at timestamp with time zone default now(),
22+
updated_at timestamp with time zone,
23+
24+
constraint fk_rule
25+
foreign key (rule_id) references scenario_workflow_rules (id)
26+
on delete cascade
27+
);
28+
29+
create table scenario_workflow_actions (
30+
id uuid primary key default gen_random_uuid(),
31+
rule_id uuid not null,
32+
action text not null,
33+
params jsonb,
34+
created_at timestamp with time zone default now(),
35+
updated_at timestamp with time zone,
36+
37+
constraint fk_rule
38+
foreign key (rule_id) references scenario_workflow_rules (id)
39+
on delete cascade
40+
);
41+
42+
-- +goose Down
43+
44+
drop table scenario_workflow_conditions;
45+
drop table scenario_workflow_rules;

0 commit comments

Comments
 (0)