Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions mdl-examples/bug-tests/308-commit-on-error-rollback-roundtrip.mdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
-- ============================================================================
-- Bug #308: `commit ... on error rollback` lost during describe → exec → describe
-- ============================================================================
--
-- Symptom (before fix):
-- Authoring `commit $X on error rollback;` and then re-executing the
-- describe output silently dropped the `on error rollback` clause —
-- subsequent describes printed plain `commit $X;`. In Studio Pro the
-- "Action call action" still showed Rollback, but mxcli's view of the
-- model diverged from the BSON, so any further mutation could mis-write
-- the field.
--
-- Root cause:
-- The commit writer omitted `ErrorHandlingType` when its value was
-- Rollback (treating Rollback as implicit). The parser then left the
-- absent field as the empty string, so the describer printed `commit $X`
-- without a clause.
--
-- After fix:
-- Parser defaults absent commit `ErrorHandlingType` to Rollback; the
-- writer always emits the field, defaulting to Rollback. The behaviour
-- is symmetric and round-trips cleanly.
--
-- Usage:
-- mxcli exec mdl-examples/bug-tests/308-commit-on-error-rollback-roundtrip.mdl -p app.mpr
-- mxcli -p app.mpr -c "describe microflow BugTest308.MF_CommitRollback"
-- The output must contain `on error rollback` and must be a fixpoint
-- under describe → exec → describe.
-- ============================================================================

create module BugTest308;

create entity BugTest308.Item (
Name : string(100)
);
/

create microflow BugTest308.MF_CommitRollback (
$Item: BugTest308.Item
)
begin
commit $Item on error rollback;
end;
/

-- Negative control: explicit `on error continue` must survive equally.
create microflow BugTest308.MF_CommitContinue (
$Item: BugTest308.Item
)
begin
commit $Item on error continue;
end;
/
5 changes: 3 additions & 2 deletions sdk/mpr/parser_microflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -714,8 +714,9 @@ func parseCommitAction(raw map[string]any) *microflows.CommitObjectsAction {
action.CommitVariable = extractString(raw["CommitVariableName"])
action.WithEvents = extractBool(raw["WithEvents"], false)
action.RefreshInClient = extractBool(raw["RefreshInClient"], false)
if errType, ok := raw["ErrorHandlingType"].(string); ok {
action.ErrorHandlingType = microflows.ErrorHandlingType(errType)
action.ErrorHandlingType = microflows.ErrorHandlingType(extractString(raw["ErrorHandlingType"]))
if action.ErrorHandlingType == "" {
action.ErrorHandlingType = microflows.ErrorHandlingTypeRollback
}
return action
}
Expand Down
34 changes: 34 additions & 0 deletions sdk/mpr/parser_microflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,37 @@ func TestParseSequenceFlow_NewCaseValueNoCase(t *testing.T) {
t.Fatalf("expected *NoCase, got %T", flow.CaseValue)
}
}

func TestParseCommitAction_ErrorHandlingTypeExplicit(t *testing.T) {
action := parseCommitAction(map[string]any{
"$ID": "commit-1",
"CommitVariableName": "Order",
"WithEvents": true,
"RefreshInClient": false,
"ErrorHandlingType": "Continue",
})

if action.ErrorHandlingType != microflows.ErrorHandlingTypeContinue {
t.Errorf("expected Continue, got %q", action.ErrorHandlingType)
}
if action.CommitVariable != "Order" {
t.Errorf("expected CommitVariable Order, got %q", action.CommitVariable)
}
}

func TestParseCommitAction_ErrorHandlingTypeDefaultsToRollback(t *testing.T) {
// When ErrorHandlingType is absent from BSON, the describer must still
// emit "on error rollback" — matching Mendix Studio Pro's default.
// Without this default, describe → exec → describe drops the suffix
// because the writer omits the field when it equals Rollback.
action := parseCommitAction(map[string]any{
"$ID": "commit-1",
"CommitVariableName": "Order",
"WithEvents": false,
"RefreshInClient": false,
})

if action.ErrorHandlingType != microflows.ErrorHandlingTypeRollback {
t.Errorf("expected default Rollback, got %q", action.ErrorHandlingType)
}
}
11 changes: 4 additions & 7 deletions sdk/mpr/writer_microflow_actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,17 +126,14 @@ func serializeMicroflowAction(action microflows.MicroflowAction) bson.D {
return doc

case *microflows.CommitObjectsAction:
doc := bson.D{
return bson.D{
{Key: "$ID", Value: idToBsonBinary(string(a.ID))},
{Key: "$Type", Value: "Microflows$CommitAction"},
{Key: "CommitVariableName", Value: a.CommitVariable},
{Key: "ErrorHandlingType", Value: stringOrDefault(string(a.ErrorHandlingType), "Rollback")},
{Key: "RefreshInClient", Value: a.RefreshInClient},
{Key: "WithEvents", Value: a.WithEvents},
}
if a.ErrorHandlingType != "" && a.ErrorHandlingType != microflows.ErrorHandlingTypeRollback {
doc = append(doc, bson.E{Key: "ErrorHandlingType", Value: string(a.ErrorHandlingType)})
}
doc = append(doc, bson.E{Key: "RefreshInClient", Value: a.RefreshInClient})
doc = append(doc, bson.E{Key: "WithEvents", Value: a.WithEvents})
return doc

case *microflows.DeleteObjectAction:
return bson.D{
Expand Down