ALTER ENTITIES — the bulk ADD ATTRIBUTE form - #1136
Merged
Merged
Conversation
Giving every entity in a module an audit trail cost one statement per
entity. Measured on a real module: 10 statements, ~242 tokens, against one
statement at ~25 -- and at 200 entities the single-entity form is ~9,700
tokens of near-identical text for an agent to emit and a human to review.
alter entities in Sales
add attribute if not exists CreatedDate: AutoCreatedDate,
add attribute if not exists ChangedDate: AutoChangedDate
where persistent;
Scope is deliberately narrow, following ALTER PAGES, which is bulk for
exactly one operation. ADD ATTRIBUTE only: DROP and RENAME aimed at a set
are destructive by a typo, and SET POSITION on every entity is meaningless.
WHERE reuses the persistence words CREATE ENTITY already uses rather than
inventing a predicate language, so no new lexer token was needed.
The executor resolves the target set and then runs each action through
execAlterEntity UNCHANGED. That delegation is the design: the single-entity
path already carries the reserved-word refusals, access-rule reconciliation,
the IF NOT EXISTS skip and write elision, and a second implementation would
have to be kept in step with all of it.
Three exclusions, and mxbuild taught me two of them -- the first version of
this passed every unit test and produced a project with 12 errors:
- A VIEW entity is never a target, with or without a filter. Its columns
come from its OQL select list, so an added attribute is CE6770 "View
Entity is out of sync with the OQL Query" (10 of the 12).
- A SPECIALIZATION whose ancestor is also a target is skipped: the same
name on a generalization and its child is CE0069 "Duplicate member
name" (the other 2, on DmTest.Vehicle/Truck/PassengerCar). The parent is
kept and the child inherits the member, which is what the author wanted.
- An UNSCOPED sweep skips System and every Marketplace module, and reports
which. An upgrade replaces those modules and takes the attribute with
it, so the write would be silently undone later rather than refused now.
Naming a module with IN is taken as meaning it, the same division
`mxcli layout` makes.
Verified on a real 11.14 project: one statement gives all 5 persistent
entities in a module both audit members, a re-run reports each as already
present, and an unscoped sweep skips 8 System/Marketplace modules and
touches only the 2 user ones. mxbuild is clean -- the doctype script now
exercises all three filter forms and `TestMxCheck_DoctypeScripts` passes at
0 errors, having failed at 12 before the exclusions.
Full stack per the checklist: grammar, AST, visitor, executor, syntax topic,
quick reference, doctype example, and tests at the parser and executor
layers. The registry handler-count snapshot is updated, which is the guard
working as intended.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BNDe35kDNsMX5cz4Ahn4rk
AI Code ReviewSummaryThe PR adds bulk What Looks Good
RecommendationApprove. The PR fully addresses the checklist requirements:
The feature solves the stated problem (reducing boilerplate for audit trails) while maintaining all existing safety guarantees. The implementation is minimal, correct, and well-tested. Automated review via OpenRouter (Nemotron Super 120B) — workflow source |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Giving every entity in a module an audit trail cost one statement per entity. Measured on a real module: 10 statements, ~242 tokens, against one statement at ~25 — and at 200 entities the single-entity form is ~9,700 tokens of near-identical text for an agent to emit and a human to review.
Design
Scope is deliberately narrow, following
ALTER PAGES, which is bulk for exactly one operation. ADD ATTRIBUTE only —DROPandRENAMEaimed at a set are destructive by a typo, andSET POSITIONon every entity is meaningless.WHEREreuses the persistence wordsCREATE ENTITYalready uses rather than inventing a predicate language, so no new lexer token was needed.The executor resolves the target set and then runs each action through
execAlterEntityunchanged. That delegation is the design: the single-entity path already carries the reserved-word refusals, access-rule reconciliation, theIF NOT EXISTSskip and write elision, and a second implementation would have to be kept in step with all of it.Three exclusions — mxbuild taught me two of them
The first version passed every unit test and produced a project with 12 errors:
DmTest.Vehicle/Truck/PassengerCar. The parent is kept and the child inherits the member, which is what the author wanted anyway.INis taken as meaning it — the same divisionmxcli layoutmakes.The first two are the interesting ones: they are not expressible as grammar or as a check on the statement, only as knowledge about what Mendix will accept. Unit tests could not have found them, and did not.
Verification
On a real 11.14 project:
TestMxCheck_DoctypeScripts/01-domain-modelpasses at 0 errors, having failed at 12 before the exclusions. The doctype script now exercises all three filter forms. Wholemdl/executorintegration package: 0 failures, 200s.make lint-goandmake testpass.Tests at both layers: 8 executor tests (filters, view exclusion, inheritance skip, marketplace guard, unknown module) and 4 parser tests, including one that the single-entity form still parses.
The registry handler-count snapshot needed updating — that guard working as intended.
🤖 Generated with Claude Code
https://claude.ai/code/session_01BNDe35kDNsMX5cz4Ahn4rk