Skip to content

Commit 5a531c2

Browse files
akoclaude
andcommitted
feat: add version pre-checks to executor commands before BSON writes
Add checkFeature() helper that queries the YAML registry and returns actionable errors with version requirement, current version, and hint. Pre-checks added to: - CREATE VIEW ENTITY (requires 10.18+) - CREATE PAGE with parameters (requires 11.0+) - CREATE REST CLIENT (requires 10.1+) - EXECUTE DATABASE QUERY (requires 10.6+, runtime connection 11.0+) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 8639f44 commit 5a531c2

File tree

5 files changed

+69
-0
lines changed

5 files changed

+69
-0
lines changed

mdl/executor/cmd_entities.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,13 @@ func (e *Executor) execCreateViewEntity(s *ast.CreateViewEntityStmt) error {
237237
return fmt.Errorf("not connected to a project")
238238
}
239239

240+
// Version pre-check
241+
if err := e.checkFeature("domain_model", "view_entities",
242+
"CREATE VIEW ENTITY",
243+
"upgrade your project to 10.18+ or use a regular entity with a microflow data source"); err != nil {
244+
return err
245+
}
246+
240247
// Validate OQL syntax before creating the view entity
241248
// This prevents creating view entities that will crash Studio Pro
242249
if s.Query.RawQuery != "" {

mdl/executor/cmd_features.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,40 @@ import (
1010
"github.com/mendixlabs/mxcli/sdk/versions"
1111
)
1212

13+
// checkFeature verifies that a feature is available in the connected project's
14+
// version. Returns nil if available, or an actionable error with the version
15+
// requirement and a hint. Safe to call when e.reader is nil (returns nil).
16+
func (e *Executor) checkFeature(area, name, statement, hint string) error {
17+
if e.reader == nil {
18+
return nil // No project connected; skip check
19+
}
20+
reg, err := versions.Load()
21+
if err != nil {
22+
return nil // Registry unavailable; don't block execution
23+
}
24+
rpv := e.reader.ProjectVersion()
25+
pv := versions.SemVer{Major: rpv.MajorVersion, Minor: rpv.MinorVersion, Patch: rpv.PatchVersion}
26+
if reg.IsAvailable(area, name, pv) {
27+
return nil
28+
}
29+
30+
// Find the min_version for the error message.
31+
features := reg.FeaturesForVersion(versions.SemVer{Major: 99, Minor: 0, Patch: 0})
32+
minV := "a newer version"
33+
for _, f := range features {
34+
if f.Area == area && f.Name == name {
35+
minV = "Mendix " + f.MinVersion.String() + "+"
36+
break
37+
}
38+
}
39+
40+
msg := fmt.Sprintf("%s requires %s (project is %s)", statement, minV, rpv.ProductVersion)
41+
if hint != "" {
42+
msg += "\n hint: " + hint
43+
}
44+
return fmt.Errorf("%s", msg)
45+
}
46+
1347
// execShowFeatures handles SHOW FEATURES, SHOW FEATURES FOR VERSION, and
1448
// SHOW FEATURES ADDED SINCE commands.
1549
func (e *Executor) execShowFeatures(s *ast.ShowFeaturesStmt) error {

mdl/executor/cmd_microflows_builder_calls.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,18 @@ func (fb *flowBuilder) addSendRestRequestAction(s *ast.SendRestRequestStmt) mode
798798

799799
// addExecuteDatabaseQueryAction creates an EXECUTE DATABASE QUERY statement.
800800
func (fb *flowBuilder) addExecuteDatabaseQueryAction(s *ast.ExecuteDatabaseQueryStmt) model.ID {
801+
// Version pre-check: database connector requires 10.6+
802+
if fb.reader != nil {
803+
pv := fb.reader.ProjectVersion()
804+
if !pv.IsAtLeast(10, 6) {
805+
fb.addError("EXECUTE DATABASE QUERY requires Mendix 10.6+ (project is %s)\n hint: upgrade your project to 10.6+", pv.ProductVersion)
806+
}
807+
// Runtime connection override requires 11.0+
808+
if len(s.ConnectionArguments) > 0 && !pv.IsAtLeast(11, 0) {
809+
fb.addError("EXECUTE DATABASE QUERY with runtime connection override requires Mendix 11.0+ (project is %s)", pv.ProductVersion)
810+
}
811+
}
812+
801813
// DynamicQuery is a Mendix expression — string literals need single quotes
802814
dynamicQuery := s.DynamicQuery
803815
if dynamicQuery != "" && !strings.HasPrefix(dynamicQuery, "'") {

mdl/executor/cmd_pages_create_v3.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ func (e *Executor) execCreatePageV3(s *ast.CreatePageStmtV3) error {
1919
return fmt.Errorf("not connected to a project")
2020
}
2121

22+
// Version pre-check: page parameters require 11.0+
23+
if len(s.Parameters) > 0 {
24+
if err := e.checkFeature("pages", "page_parameters",
25+
"CREATE PAGE with parameters",
26+
"pass data via a non-persistent entity or microflow parameter instead"); err != nil {
27+
return err
28+
}
29+
}
30+
2231
// Find or auto-create module
2332
module, err := e.findOrCreateModule(s.Name.Module)
2433
if err != nil {

mdl/executor/cmd_rest_clients.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,13 @@ func (e *Executor) createRestClient(stmt *ast.CreateRestClientStmt) error {
216216
return fmt.Errorf("not connected to a project (read-only mode)")
217217
}
218218

219+
// Version pre-check: REST clients require 10.1+
220+
if err := e.checkFeature("integration", "rest_client_basic",
221+
"CREATE REST CLIENT",
222+
"upgrade your project to 10.1+"); err != nil {
223+
return err
224+
}
225+
219226
moduleName := stmt.Name.Module
220227
module, err := e.findModule(moduleName)
221228
if err != nil {

0 commit comments

Comments
 (0)