Skip to content

Commit 5a3076e

Browse files
akoclaude
andcommitted
fix: event handler BSON field names and explicit parameter syntax
Parser: read from Events (not EventHandlers), Type (not Event), SendInputParameter (not PassEventObject) with fallbacks for both. Writer: emit DomainModels$EntityEvent (not DomainModels$EventHandler), Type (not Event), SendInputParameter (not PassEventObject). Grammar: event handlers now support ($currentObject) to pass the entity object, or () to skip it. DESCRIBE shows the parameter explicitly and only outputs RAISE ERROR on BEFORE handlers. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 7827200 commit 5a3076e

File tree

11 files changed

+7384
-7214
lines changed

11 files changed

+7384
-7214
lines changed

cmd/mxcli/help_topics/entity.txt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,29 @@ Complete Example:
8282
)
8383
INDEX (Email)
8484
COMMENT 'Stores customer information';
85+
86+
Event Handlers:
87+
ON BEFORE|AFTER CREATE|COMMIT|DELETE|ROLLBACK CALL Module.Microflow(...) [RAISE ERROR]
88+
89+
Parameter syntax:
90+
($currentObject) - Microflow receives the entity object
91+
() - Microflow receives no object parameter
92+
(no parens) - Same as ($currentObject), default
93+
94+
Rules:
95+
- BEFORE handlers return Boolean. RAISE ERROR aborts when false.
96+
- AFTER handlers return Void. Cannot use RAISE ERROR.
97+
98+
Add via ALTER ENTITY:
99+
ALTER ENTITY MyModule.Customer
100+
ADD EVENT HANDLER ON BEFORE COMMIT CALL MyModule.Validate($currentObject) RAISE ERROR;
101+
102+
ALTER ENTITY MyModule.Customer
103+
ADD EVENT HANDLER ON AFTER COMMIT CALL MyModule.LogChange();
104+
105+
Or directly on CREATE ENTITY:
106+
CREATE PERSISTENT ENTITY MyModule.Order (
107+
Name: String(100)
108+
)
109+
ON BEFORE COMMIT CALL MyModule.ValidateOrder($currentObject) RAISE ERROR
110+
ON AFTER COMMIT CALL MyModule.LogOrderChange($currentObject);

docs-site/src/language/alter-entity.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,37 @@ ALTER ENTITY Sales.Order DROP STORE OWNER;
111111
ALTER ENTITY Sales.Order DROP STORE CHANGED DATE;
112112
```
113113

114+
## ADD/DROP EVENT HANDLER
115+
116+
Register microflows to run before or after entity operations:
117+
118+
```sql
119+
-- Before commit: validates and can abort (RAISE ERROR)
120+
ALTER ENTITY Sales.Order
121+
ADD EVENT HANDLER ON BEFORE COMMIT CALL Sales.ValidateOrder($currentObject) RAISE ERROR;
122+
123+
-- After commit: runs after successful commit (no RAISE ERROR)
124+
ALTER ENTITY Sales.Order
125+
ADD EVENT HANDLER ON AFTER COMMIT CALL Sales.LogOrderChange($currentObject);
126+
127+
-- Without passing the entity object
128+
ALTER ENTITY Sales.Order
129+
ADD EVENT HANDLER ON AFTER CREATE CALL Sales.NotifyNewOrder();
130+
131+
-- Remove an event handler
132+
ALTER ENTITY Sales.Order
133+
DROP EVENT HANDLER ON BEFORE COMMIT;
134+
```
135+
136+
| Moment | Returns | RAISE ERROR | Use case |
137+
|--------|---------|-------------|----------|
138+
| `BEFORE` | Boolean | Yes — aborts on `false` | Validation, permission checks |
139+
| `AFTER` | Void | No | Logging, notifications, side effects |
140+
141+
Events: `CREATE`, `COMMIT`, `DELETE`, `ROLLBACK`
142+
143+
Parameter: `($currentObject)` passes the entity to the microflow, `()` does not.
144+
114145
## Syntax Summary
115146

116147
```sql

docs/01-project/MDL_QUICK_REFERENCE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ Modifies an existing entity without full replacement.
6464
| Rename attribute | `ALTER ENTITY Module.Name RENAME OldName TO NewName;` | |
6565
| Add index | `ALTER ENTITY Module.Name ADD INDEX (Col1 [ASC\|DESC], ...);` | |
6666
| Drop index | `ALTER ENTITY Module.Name DROP INDEX (Col1, ...);` | |
67-
| Add event handler | `ALTER ENTITY Module.Name ADD EVENT HANDLER ON BEFORE COMMIT CALL Mod.MF [RAISE ERROR];` | Moments: BEFORE/AFTER, Events: CREATE/COMMIT/DELETE/ROLLBACK |
67+
| Add event handler | `ALTER ENTITY Module.Name ADD EVENT HANDLER ON BEFORE COMMIT CALL Mod.MF($currentObject) [RAISE ERROR];` | `($currentObject)` or `()`, RAISE ERROR only on BEFORE |
6868
| Drop event handler | `ALTER ENTITY Module.Name DROP EVENT HANDLER ON BEFORE COMMIT;` | |
6969
| Set documentation | `ALTER ENTITY Module.Name SET DOCUMENTATION 'text';` | |
7070
| Set position | `ALTER ENTITY Module.Name SET POSITION (100, 200);` | Canvas position |

mdl-examples/doctype-tests/26-system-attribute-examples.mdl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,26 @@ CREATE OR MODIFY PERSISTENT ENTITY SysAttrTest.TempRecord (
7070
-- Disable both flags
7171
ALTER ENTITY SysAttrTest.TempRecord DROP STORE OWNER;
7272
ALTER ENTITY SysAttrTest.TempRecord DROP STORE CREATED DATE;
73+
74+
-- ============================================================================
75+
-- Example 5: Entity with event handlers
76+
-- ============================================================================
77+
78+
CREATE MICROFLOW SysAttrTest.ACT_ValidateOrder ($Order: SysAttrTest.AuditedRecord)
79+
RETURNS Boolean
80+
BEGIN
81+
RETURN true;
82+
END;
83+
84+
CREATE MICROFLOW SysAttrTest.ACT_AfterCommitOrder ($Order: SysAttrTest.AuditedRecord)
85+
BEGIN
86+
RETURN empty;
87+
END;
88+
89+
-- RAISE ERROR: only valid on BEFORE handlers (microflow returns Boolean, false = abort)
90+
ALTER ENTITY SysAttrTest.AuditedRecord
91+
ADD EVENT HANDLER ON BEFORE COMMIT CALL SysAttrTest.ACT_ValidateOrder RAISE ERROR;
92+
93+
-- AFTER handlers cannot RAISE ERROR (microflow returns Void)
94+
ALTER ENTITY SysAttrTest.AuditedRecord
95+
ADD EVENT HANDLER ON AFTER COMMIT CALL SysAttrTest.ACT_AfterCommitOrder;

mdl/executor/cmd_entities_describe.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -401,18 +401,24 @@ func (e *Executor) describeEntity(name ast.QualifiedName) error {
401401
if mfName == "" {
402402
continue
403403
}
404-
raise := ""
405-
if eh.RaiseErrorOnFalse {
406-
raise = " RAISE ERROR"
407-
}
408404
eventName := string(eh.Event)
409405
if eventName == "RollBack" {
410406
eventName = "ROLLBACK"
411407
} else {
412408
eventName = strings.ToUpper(eventName)
413409
}
414-
fmt.Fprintf(e.output, "\nON %s %s CALL %s%s",
415-
strings.ToUpper(string(eh.Moment)), eventName, mfName, raise)
410+
// Show parameter: ($currentObject) or ()
411+
paramStr := "()"
412+
if eh.PassEventObject {
413+
paramStr = "($currentObject)"
414+
}
415+
var options string
416+
// RAISE ERROR only applies to Before handlers (they return Boolean)
417+
if eh.RaiseErrorOnFalse && strings.EqualFold(string(eh.Moment), "Before") {
418+
options = " RAISE ERROR"
419+
}
420+
fmt.Fprintf(e.output, "\nON %s %s CALL %s%s%s",
421+
strings.ToUpper(string(eh.Moment)), eventName, mfName, paramStr, options)
416422
}
417423

418424
fmt.Fprintln(e.output, ";")

mdl/grammar/MDLParser.g4

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -550,9 +550,10 @@ entityOption
550550
| eventHandlerDefinition
551551
;
552552

553-
// Entity event handler: ON BEFORE/AFTER CREATE/COMMIT/DELETE/ROLLBACK CALL Mod.Microflow [RAISE ERROR]
553+
// Entity event handler: ON BEFORE/AFTER CREATE/COMMIT/DELETE/ROLLBACK CALL Mod.Microflow($currentObject) [RAISE ERROR]
554+
// Empty parens () = don't pass object, ($currentObject) = pass object, no parens = pass object (default)
554555
eventHandlerDefinition
555-
: ON eventMoment eventType CALL qualifiedName (RAISE ERROR)?
556+
: ON eventMoment eventType CALL qualifiedName (LPAREN VARIABLE? RPAREN)? (RAISE ERROR)?
556557
;
557558

558559
eventMoment

mdl/grammar/parser/MDLParser.interp

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)