Skip to content

Commit 2d2c747

Browse files
akoclaude
andcommitted
fix: support multiple XPath predicates [cond1][cond2] in WHERE clauses
Consecutive bracket predicates without explicit AND/OR are now parsed as implicit AND, matching standard Mendix XPath syntax. Fixes #144. Also adds `mxcli syntax xpath` help topic and updates the xpath skill. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 4088019 commit 2d2c747

7 files changed

Lines changed: 5359 additions & 5128 deletions

File tree

.claude/skills/mendix/xpath-constraints.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,13 @@ DATAGRID dg (
167167
}
168168
```
169169

170-
Multiple bracket constraints can be chained:
170+
Multiple bracket constraints can be chained. Consecutive brackets without an operator are treated as AND (standard Mendix XPath):
171171

172172
```mdl
173-
-- All AND: separate brackets
173+
-- Consecutive brackets (implicit AND) — standard Mendix XPath syntax
174+
DataSource: DATABASE FROM Module.Entity WHERE [IsActive = true][Stock > 0]
175+
176+
-- Explicit AND: same result
174177
DataSource: DATABASE FROM Module.Entity WHERE [IsActive = true] AND [Stock > 0]
175178
176179
-- Mix with OR: combines into single bracket

cmd/mxcli/help.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ Available topics:
176176
fragment - Show fragment (reusable widget group) syntax
177177
java-action - Show Java action syntax (CREATE/DESCRIBE/CALL, type params, EXPOSED AS)
178178
business-events - Show business event service syntax
179+
xpath - Show XPath constraint syntax for WHERE clauses
179180
oql - Show OQL query execution syntax (mxcli oql)
180181
sql - Show external SQL query execution syntax (mxcli sql)
181182
errors - List validation errors and how to fix them
@@ -240,6 +241,8 @@ Example:
240241
showTopicHelp("java-action")
241242
case "business-events", "businessevents", "business_events", "be":
242243
showTopicHelp("business-events")
244+
case "xpath", "xpath-constraints":
245+
showTopicHelp("xpath")
243246
case "oql":
244247
showTopicHelp("oql")
245248
case "sql", "external-sql":

cmd/mxcli/help_topics/xpath.txt

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
XPath Constraints in MDL
2+
========================
3+
4+
XPath expressions filter data in RETRIEVE statements, page data sources,
5+
conditional visibility/editability, and security rules.
6+
7+
SYNTAX
8+
------
9+
10+
Single predicate: WHERE [condition]
11+
Multiple predicates: WHERE [cond1][cond2] -- implicit AND
12+
Explicit operators: WHERE [cond1] AND [cond2]
13+
WHERE [cond1] OR [cond2]
14+
15+
OPERATORS
16+
---------
17+
18+
=, !=, <, >, <=, >= Comparison
19+
and, or Boolean (lowercase in XPath)
20+
not(expr) Negation function
21+
contains(attr, 'text') String contains
22+
starts-with(attr, 'text') String starts-with
23+
true(), false() Boolean literals
24+
25+
EXAMPLES
26+
--------
27+
28+
-- Simple comparison
29+
WHERE [Status = 'Active']
30+
WHERE [Amount >= 100]
31+
32+
-- Multiple predicates (implicit AND)
33+
WHERE [IsActive = true][Stock > 0]
34+
35+
-- Boolean logic
36+
WHERE [State = 'Ready' and Priority > 5]
37+
WHERE [State = 'Pending' or State = 'Processing']
38+
WHERE [not(IsArchived)]
39+
40+
-- Association path traversal
41+
WHERE [Module.Order_Customer/Module.Customer/Name = $Name]
42+
43+
-- Nested predicates on path steps
44+
WHERE [Module.Line_Order/Module.Order[State = 'Active']/Total > 100]
45+
46+
-- Mendix tokens (runtime values)
47+
WHERE [System.owner = '[%CurrentUser%]']
48+
WHERE [CreatedDate > [%CurrentDateTime%]]
49+
50+
-- ID pseudo-attribute
51+
WHERE [id = $currentObject]
52+
53+
USAGE CONTEXTS
54+
--------------
55+
56+
Microflow RETRIEVE:
57+
RETRIEVE $Orders FROM Module.Order
58+
WHERE [State = 'Completed'][IsPaid = true]
59+
SORT BY OrderDate DESC;
60+
61+
Page data source:
62+
DATAGRID dg (
63+
DataSource: DATABASE FROM Module.Order
64+
WHERE [State != 'Cancelled'][Amount > 0]
65+
SORT BY OrderDate DESC
66+
)
67+
68+
Conditional visibility:
69+
CONTAINER c (Visible: [IsActive = true])
70+
71+
Conditional editability:
72+
TEXTBOX txt (Editable: [Status != 'Closed'])
73+
74+
Security (string literal):
75+
GRANT Module.Role ON Module.Entity (READ *)
76+
WHERE '[System.owner = ''[%CurrentUser%]'']';
77+
78+
DIFFERENCES FROM MENDIX EXPRESSIONS
79+
------------------------------------
80+
81+
XPath [...] Mendix expression
82+
───────────── ──────────────────
83+
/ is path traversal / is also division
84+
and, or (lowercase) AND, OR (uppercase)
85+
not(expr) function NOT expr keyword
86+
'[%CurrentUser%]' (quoted) [%CurrentUser%] (unquoted)

mdl/grammar/MDLParser.g4

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,7 +1192,7 @@ rollbackStatement
11921192
// RETRIEVE $ProductList FROM MfTest.Product WHERE Code = $SearchCode SORT BY Name ASC LIMIT 1;
11931193
retrieveStatement
11941194
: RETRIEVE VARIABLE FROM retrieveSource
1195-
(WHERE (xpathConstraint | expression))?
1195+
(WHERE (xpathConstraint (andOrXpath? xpathConstraint)* | expression))?
11961196
(SORT_BY sortColumn (COMMA sortColumn)*)?
11971197
(LIMIT limitExpr=expression)?
11981198
(OFFSET offsetExpr=expression)?
@@ -2027,7 +2027,7 @@ attributeListV3
20272027
dataSourceExprV3
20282028
: VARIABLE // $ParamName
20292029
| DATABASE FROM? qualifiedName // DATABASE [FROM] Entity [WHERE ...] [SORT BY ...]
2030-
(WHERE (xpathConstraint (andOrXpath xpathConstraint)* | expression))?
2030+
(WHERE (xpathConstraint (andOrXpath? xpathConstraint)* | expression))?
20312031
(SORT_BY sortColumn (COMMA sortColumn)*)?
20322032
| MICROFLOW qualifiedName microflowArgsV3? // MICROFLOW Module.Flow
20332033
| NANOFLOW qualifiedName microflowArgsV3? // NANOFLOW Module.Flow

mdl/grammar/parser/MDLParser.interp

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

0 commit comments

Comments
 (0)