Skip to content

fix: preserve multiple retrieve XPath predicates#500

Merged
ako merged 1 commit intomendixlabs:mainfrom
hjotha:submit/retrieve-preserve-multiple-xpath-predicates
May 2, 2026
Merged

fix: preserve multiple retrieve XPath predicates#500
ako merged 1 commit intomendixlabs:mainfrom
hjotha:submit/retrieve-preserve-multiple-xpath-predicates

Conversation

@hjotha
Copy link
Copy Markdown
Contributor

@hjotha hjotha commented May 2, 2026

Closes #499.

Summary

  • preserves bracketed source for retrieve where clauses with multiple XPath predicates
  • writes already-bracketed retrieve XPath source without adding an extra wrapper predicate
  • adds synthetic regression coverage for predicate-boundary preservation

Validation

  • ./bin/mxcli check mdl-examples/bug-tests/retrieve-multiple-xpath-predicates.mdl
  • make build
  • make lint-go
  • make test

Symptom: a retrieve authored with multiple XPath predicates could round-trip as one combined predicate. When an earlier predicate contained `or`, serializing `[A or B][C][D]` as `[A or B and C and D]` changed XPath precedence.

Root cause: the microflow visitor parsed multiple `xpathConstraint` nodes into a chained `and` expression and discarded the original predicate boundaries. The builder then wrapped the expression as a single XPathConstraint.

Fix: preserve the bracketed predicate source on the retrieve `where` expression and let the builder write already-bracketed XPath source without adding another pair of brackets.

Tests: add visitor coverage for preserving multiple predicate boundaries, builder coverage for writing bracketed predicates unchanged, and a synthetic bug-test fixture for the retrieve form.
@ako
Copy link
Copy Markdown
Collaborator

ako commented May 2, 2026

Review: fix: preserve multiple retrieve XPath predicates

Verdict: Approve with minor note

What the PR does

Fixes issue #499: retrieve ... where [A or B][C][D] was being stored in BSON as [A or B and C and D], silently changing operator precedence. The visitor combined multiple predicates into a flat BinaryExpr and chain; the builder then wrapped the whole thing in one outer [...].

Three-part fix:

  1. Visitor — wraps the combined BinaryExpr in ast.SourceExpr{Source: "[pred1][pred2][pred3]"} when all predicates yield source text, preserving predicate boundaries.
  2. Builder — new retrieveXPathConstraint: if expressionToXPath returns a string already starting and ending with [/], use it as-is; otherwise wrap it. expressionToXPath on a SourceExpr returns e.Source directly (existing behaviour at cmd_microflows_helpers.go:387), so the multi-predicate case reaches the builder unchanged.
  3. MDL bug test + unit tests — visitor test for source preservation, builder test that the XPathConstraint field matches the original bracketed form exactly.

No blockers

Minor: bracket-presence check is a heuristic

retrieveXPathConstraint detects an already-wrapped constraint by checking HasPrefix(xpath, "[") && HasSuffix(xpath, "]"). This is correct for every practical Mendix XPath shape (single predicate, multi-predicate, Mendix tokens like [%CurrentDateTime%]), but it is not a full bracket parser — a pathological input that starts with [ but closes it mid-string would be misclassified. Given that expressionToXPath on a SourceExpr always returns the raw parser source (which the visitor only sets when it has a valid bracketed shape), this can't occur in practice. Worth a one-line comment on the function noting the assumption.

Positive notes

  • The len(predicateSources) == len(andExprs) guard is correct: if any predicate fails to produce source text the code falls back to the previous BinaryExpr chain, so the fix degrades gracefully
  • Single-predicate path is untouched — buildXPathSourceExpression returns SourceExpr{Source: "inner"} (no brackets), expressionToXPath returns "inner", retrieveXPathConstraint wraps it → [inner]
  • MDL bug test reproduces the exact user-facing symptom and documents the manual round-trip expectation
  • Clean PR — no bundled unrelated changes

@ako ako merged commit 74ece63 into mendixlabs:main May 2, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Retrieve roundtrip loses XPath predicate boundaries

3 participants