Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ BEGIN
END;
/

CREATE MICROFLOW PrsTest.PRS_GetOrderById ($httpResponse: System.HttpResponse, $Id: String)
CREATE MICROFLOW PrsTest.PRS_GetOrderById ($httpResponse: System.HttpResponse, $id: String)
RETURNS String AS $Result
BEGIN
DECLARE $Result String = '{}';
Expand All @@ -39,7 +39,7 @@ BEGIN
END;
/

CREATE MICROFLOW PrsTest.PRS_DeleteOrder ($httpResponse: System.HttpResponse, $Id: String)
CREATE MICROFLOW PrsTest.PRS_DeleteOrder ($httpResponse: System.HttpResponse, $id: String)
RETURNS String AS $Result
BEGIN
DECLARE $Result String = '{"status": "deleted"}';
Expand Down
42 changes: 30 additions & 12 deletions mdl-examples/doctype-tests/workflow-microflow-actions.mdl
Original file line number Diff line number Diff line change
@@ -1,10 +1,37 @@
-- Test: workflow microflow actions syntax
-- Verifies parsing of all 11 workflow action types in microflows

-- ############################################################################
-- PREREQUISITES
-- ############################################################################

CREATE PERSISTENT ENTITY TestModule.DeliveryContext (
OrderID: String(50),
Status: String(100)
);

CREATE MICROFLOW TestModule.ACT_Stub ($DeliveryContext: TestModule.DeliveryContext)
BEGIN
@position(200,200) RETURN;
END;
/

CREATE WORKFLOW TestModule.WF_DeliveryDelay
PARAMETER $WorkflowContext: TestModule.DeliveryContext
DISPLAY 'Delivery Delay'
BEGIN
CALL MICROFLOW TestModule.ACT_Stub;
END WORKFLOW;
/

-- ############################################################################
-- MICROFLOW WITH ALL WORKFLOW ACTION TYPES
-- ############################################################################

CREATE MICROFLOW TestModule.MF_WorkflowActions (
$Workflow: Object,
$ContextObj: Object,
$UserTask: Object
$Workflow: System.Workflow,
$ContextObj: TestModule.DeliveryContext,
$UserTask: System.WorkflowUserTask
)
RETURNS Nothing
BEGIN
Expand Down Expand Up @@ -34,15 +61,6 @@ BEGIN
WORKFLOW OPERATION RETRY $Workflow;
WORKFLOW OPERATION UNPAUSE $Workflow;

-- Notify workflow
NOTIFY WORKFLOW $Workflow;

-- Open workflow admin page
OPEN WORKFLOW $Workflow;

-- Lock/Unlock
LOCK WORKFLOW ALL;
UNLOCK WORKFLOW ALL;
LOCK WORKFLOW $Workflow;
UNLOCK WORKFLOW $Workflow;
END;
11 changes: 11 additions & 0 deletions mdl/executor/cmd_microflows_builder_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,16 @@ func ValidateMicroflowBody(s *ast.CreateMicroflowStmt) []string {
varTypes := make(map[string]string)
declaredVars := make(map[string]string)

var paramErrors []string
for _, p := range s.Parameters {
if p.Type.EntityRef != nil {
// Reject bare entity names (empty module) — e.g., "Object" instead of "System.Workflow"
if p.Type.EntityRef.Module == "" {
paramErrors = append(paramErrors, fmt.Sprintf(
"parameter '$%s': entity type '%s' is missing module prefix (use 'Module.%s')",
p.Name, p.Type.EntityRef.Name, p.Type.EntityRef.Name))
continue
}
entityQN := p.Type.EntityRef.Module + "." + p.Type.EntityRef.Name
if p.Type.Kind == ast.TypeListOf {
varTypes[p.Name] = "List of " + entityQN
Expand All @@ -29,6 +37,9 @@ func ValidateMicroflowBody(s *ast.CreateMicroflowStmt) []string {
declaredVars[p.Name] = p.Type.Kind.String()
}
}
if len(paramErrors) > 0 {
return paramErrors
}

// Create a validation-only flow builder
fb := &flowBuilder{
Expand Down
10 changes: 10 additions & 0 deletions mdl/executor/validate_microflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ func ValidateMicroflow(stmt *ast.CreateMicroflowStmt) []linter.Violation {
mfName: stmt.Name.String(),
returnType: stmt.ReturnType,
}
// Validate parameter entity references — reject bare names without module prefix
for _, p := range stmt.Parameters {
if p.Type.EntityRef != nil && p.Type.EntityRef.Module == "" {
v.addViolation("MDL008", linter.SeverityError,
fmt.Sprintf("parameter '$%s': entity type '%s' is missing module prefix",
p.Name, p.Type.EntityRef.Name),
fmt.Sprintf("Use a qualified name like 'Module.%s' or 'System.%s'",
p.Type.EntityRef.Name, p.Type.EntityRef.Name))
}
}
v.validate(stmt.Body)
return v.violations
}
Expand Down
8 changes: 2 additions & 6 deletions mdl/visitor/visitor_rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,16 +298,12 @@ func (b *Builder) ExitCreatePublishedRestServiceStatement(ctx *parser.CreatePubl
opDef.HTTPMethod = strings.ToUpper(mCtx.GetText())
}

// Operation path
// Operation path — strip leading/trailing slashes (CE6550/CE6551)
if pCtx := oc.PublishedRestOpPath(); pCtx != nil {
pc := pCtx.(*parser.PublishedRestOpPathContext)
if pc.STRING_LITERAL() != nil {
opDef.Path = unquoteString(pc.STRING_LITERAL().GetText())
} else {
opDef.Path = "/"
opDef.Path = strings.Trim(unquoteString(pc.STRING_LITERAL().GetText()), "/")
}
} else {
opDef.Path = "/"
}

// Microflow reference
Expand Down
11 changes: 6 additions & 5 deletions model/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -602,11 +602,12 @@ type PublishedRestResource struct {
// PublishedRestOperation represents a Rest$PublishedRestServiceOperation.
type PublishedRestOperation struct {
BaseElement
Path string `json:"path,omitempty"`
HTTPMethod string `json:"httpMethod,omitempty"`
Summary string `json:"summary,omitempty"`
Microflow string `json:"microflow,omitempty"`
Deprecated bool `json:"deprecated,omitempty"`
Path string `json:"path,omitempty"`
HTTPMethod string `json:"httpMethod,omitempty"`
Summary string `json:"summary,omitempty"`
Microflow string `json:"microflow,omitempty"`
Deprecated bool `json:"deprecated,omitempty"`
Parameters []string `json:"parameters,omitempty"` // path parameter names extracted from {param} in Path
}

// ============================================================================
Expand Down
38 changes: 37 additions & 1 deletion sdk/mpr/writer_rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ func (w *Writer) serializePublishedRestService(svc *model.PublishedRestService)
"ExportMapping": "",
"ImportMapping": "",
"ObjectHandlingBackup": "Create",
"Parameters": bson.A{int32(2)},
"Parameters": serializePublishedRestParams(op.Path, op.Parameters),
}
ops = append(ops, opDoc)
}
Expand Down Expand Up @@ -377,6 +377,42 @@ func (w *Writer) serializePublishedRestService(svc *model.PublishedRestService)
return bson.Marshal(doc)
}

// serializePublishedRestParams builds the Parameters array for a published REST operation.
// It auto-extracts path parameters from {paramName} placeholders in the path string,
// then appends any explicitly declared parameters.
func serializePublishedRestParams(path string, _ []string) bson.A {
params := bson.A{int32(2)}
// Extract {paramName} from path
for _, name := range extractPathParams(path) {
params = append(params, bson.M{
"$ID": idToBsonBinary(generateUUID()),
"$Type": "Rest$RestOperationParameter",
"Name": name,
"DataType": "String",
"Description": "",
})
}
return params
}

// extractPathParams returns parameter names from {param} placeholders in a path.
func extractPathParams(path string) []string {
var names []string
for {
start := strings.Index(path, "{")
if start < 0 {
break
}
end := strings.Index(path[start:], "}")
if end < 0 {
break
}
names = append(names, path[start+1:start+end])
path = path[start+end+1:]
}
return names
}

// httpMethodToMendix converts uppercase HTTP method names to Mendix casing.
func httpMethodToMendix(method string) string {
switch strings.ToUpper(method) {
Expand Down
Loading