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
33 changes: 33 additions & 0 deletions mdl-examples/bug-tests/339-empty-change-refresh-in-client.mdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
-- ============================================================================
-- Bug #339: Empty change-object actions must refresh in client
-- ============================================================================
--
-- Symptom (before fix):
-- Rebuilding an empty change-object activity from MDL wrote a non-committing
-- ChangeObjectAction with no member changes and RefreshInClient=false.
-- Studio Pro / mx check rejected that activity with CE0032:
-- "Change action has no items specified and does not commit the object."
--
-- After fix:
-- `change $Object;` is serialized as a refresh-only change action by setting
-- RefreshInClient=true. Although the CE0032 text mentions only items/commit,
-- empirical mx check validation accepts refresh as the third valid escape.
--
-- Usage:
-- mxcli exec mdl-examples/bug-tests/339-empty-change-refresh-in-client.mdl -p app.mpr
-- mx check app.mpr
-- Expected: 0 new CE0032 errors for BugTest339.MF_RefreshOnlyChange.
-- ============================================================================

create module BugTest339;

create entity BugTest339.Item (
Name: String(100)
);

create microflow BugTest339.MF_RefreshOnlyChange ()
begin
$Item = create BugTest339.Item;
change $Item;
end;
/
21 changes: 21 additions & 0 deletions mdl/executor/bugfix_regression_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,27 @@ func TestCallMicroflowResultType_ResolvesSubsequentChangeMember(t *testing.T) {
}
}

func TestEmptyChangeObjectRefreshesInClient(t *testing.T) {
fb := &flowBuilder{posX: 100, posY: 100, spacing: HorizontalSpacing}

id := fb.addChangeObjectAction(&ast.ChangeObjectStmt{Variable: "Object"})
if id == "" || len(fb.objects) != 1 {
t.Fatalf("expected one change object activity, got id=%q objects=%d", id, len(fb.objects))
}

activity, ok := fb.objects[0].(*microflows.ActionActivity)
if !ok {
t.Fatalf("object type = %T, want *microflows.ActionActivity", fb.objects[0])
}
action, ok := activity.Action.(*microflows.ChangeObjectAction)
if !ok {
t.Fatalf("action type = %T, want *microflows.ChangeObjectAction", activity.Action)
}
if !action.RefreshInClient {
t.Fatal("empty change object must refresh in client to remain valid without member changes or commit")
}
}

func TestCallMicroflowUnknownResultTypeStillDeclaresVariable(t *testing.T) {
fb := &flowBuilder{
varTypes: map[string]string{"Result": "Old.ModuleEntity"},
Expand Down
11 changes: 7 additions & 4 deletions mdl/executor/cmd_microflows_builder_actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,13 @@ func (fb *flowBuilder) addRollbackAction(s *ast.RollbackStmt) model.ID {
// addChangeObjectAction creates a CHANGE statement.
func (fb *flowBuilder) addChangeObjectAction(s *ast.ChangeObjectStmt) model.ID {
action := &microflows.ChangeObjectAction{
BaseElement: model.BaseElement{ID: model.ID(types.GenerateID())},
ChangeVariable: s.Variable,
Commit: microflows.CommitTypeNo,
RefreshInClient: false,
BaseElement: model.BaseElement{ID: model.ID(types.GenerateID())},
ChangeVariable: s.Variable,
Commit: microflows.CommitTypeNo,
// Studio Pro rejects an empty non-committing change action unless it
// refreshes in client. The CE0032 message mentions only items/commit,
// but mx check accepts RefreshInClient=true as the third valid escape.
RefreshInClient: len(s.Changes) == 0,
}

// Look up entity type from variable scope
Expand Down