Skip to content

Commit 42c684e

Browse files
akoclaude
andcommitted
feat: implement RENAME with automatic reference refactoring
Add RENAME command for entity, microflow, nanoflow, page, enumeration, association, constant, and module. A generic BSON string scanner updates all BY_NAME references across the project. Supports DRY RUN to preview changes. Adds mxcli rename CLI subcommand. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent ac9c338 commit 42c684e

File tree

11 files changed

+8615
-7258
lines changed

11 files changed

+8615
-7258
lines changed

cmd/mxcli/cmd_rename.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package main
4+
5+
import (
6+
"fmt"
7+
"os"
8+
"strings"
9+
10+
"github.com/mendixlabs/mxcli/mdl/visitor"
11+
"github.com/spf13/cobra"
12+
)
13+
14+
var renameCmd = &cobra.Command{
15+
Use: "rename <type> <qualified-name> <new-name>",
16+
Short: "Rename a project element and update all references",
17+
Long: `Rename an element and automatically update all cross-references.
18+
19+
Types:
20+
entity Rename an entity
21+
microflow Rename a microflow
22+
nanoflow Rename a nanoflow
23+
page Rename a page
24+
enumeration Rename an enumeration
25+
association Rename an association
26+
constant Rename a constant
27+
module Rename a module (updates all qualified names)
28+
29+
Use --dry-run to preview changes without modifying.
30+
31+
Example:
32+
mxcli rename -p app.mpr entity MyModule.Customer Client
33+
mxcli rename -p app.mpr microflow MyModule.ACT_Old ACT_New
34+
mxcli rename -p app.mpr page MyModule.OldPage NewPage
35+
mxcli rename -p app.mpr module OldModule NewModule
36+
mxcli rename -p app.mpr entity MyModule.Customer Client --dry-run
37+
`,
38+
Args: cobra.ExactArgs(3),
39+
Run: func(cmd *cobra.Command, args []string) {
40+
projectPath, _ := cmd.Flags().GetString("project")
41+
if projectPath == "" {
42+
fmt.Fprintln(os.Stderr, "Error: --project (-p) is required")
43+
os.Exit(1)
44+
}
45+
46+
dryRun, _ := cmd.Flags().GetBool("dry-run")
47+
48+
objectType := strings.ToUpper(args[0])
49+
qualifiedName := args[1]
50+
newName := args[2]
51+
52+
var mdlCmd string
53+
dryRunSuffix := ""
54+
if dryRun {
55+
dryRunSuffix = " DRY RUN"
56+
}
57+
58+
switch objectType {
59+
case "ENTITY":
60+
mdlCmd = fmt.Sprintf("RENAME ENTITY %s TO %s%s", qualifiedName, newName, dryRunSuffix)
61+
case "MICROFLOW":
62+
mdlCmd = fmt.Sprintf("RENAME MICROFLOW %s TO %s%s", qualifiedName, newName, dryRunSuffix)
63+
case "NANOFLOW":
64+
mdlCmd = fmt.Sprintf("RENAME NANOFLOW %s TO %s%s", qualifiedName, newName, dryRunSuffix)
65+
case "PAGE":
66+
mdlCmd = fmt.Sprintf("RENAME PAGE %s TO %s%s", qualifiedName, newName, dryRunSuffix)
67+
case "ENUMERATION":
68+
mdlCmd = fmt.Sprintf("RENAME ENUMERATION %s TO %s%s", qualifiedName, newName, dryRunSuffix)
69+
case "ASSOCIATION":
70+
mdlCmd = fmt.Sprintf("RENAME ASSOCIATION %s TO %s%s", qualifiedName, newName, dryRunSuffix)
71+
case "CONSTANT":
72+
mdlCmd = fmt.Sprintf("RENAME CONSTANT %s TO %s%s", qualifiedName, newName, dryRunSuffix)
73+
case "MODULE":
74+
mdlCmd = fmt.Sprintf("RENAME MODULE %s TO %s%s", qualifiedName, newName, dryRunSuffix)
75+
default:
76+
fmt.Fprintf(os.Stderr, "Unknown type: %s\n", args[0])
77+
fmt.Fprintln(os.Stderr, "Valid types: entity, microflow, nanoflow, page, enumeration, association, constant, module")
78+
os.Exit(1)
79+
}
80+
81+
exec, logger := newLoggedExecutor("subcommand")
82+
defer logger.Close()
83+
defer exec.Close()
84+
85+
// Connect
86+
connectProg, _ := visitor.Build(fmt.Sprintf("CONNECT LOCAL '%s' FOR WRITING", projectPath))
87+
for _, stmt := range connectProg.Statements {
88+
if err := exec.Execute(stmt); err != nil {
89+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
90+
os.Exit(1)
91+
}
92+
}
93+
94+
// Execute rename
95+
renameProg, errs := visitor.Build(mdlCmd)
96+
if len(errs) > 0 {
97+
for _, err := range errs {
98+
fmt.Fprintf(os.Stderr, "Parse error: %v\n", err)
99+
}
100+
os.Exit(1)
101+
}
102+
103+
for _, stmt := range renameProg.Statements {
104+
if err := exec.Execute(stmt); err != nil {
105+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
106+
os.Exit(1)
107+
}
108+
}
109+
},
110+
}
111+
112+
func init() {
113+
renameCmd.Flags().Bool("dry-run", false, "Preview changes without modifying")
114+
rootCmd.AddCommand(renameCmd)
115+
}

docs/01-project/MDL_QUICK_REFERENCE.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ CREATE PERSISTENT ENTITY Module.Photo (
2828
| Describe module | `DESCRIBE MODULE ModuleName;` | All contents (entities, microflows, pages, etc.) |
2929
| Create module | `CREATE MODULE ModuleName;` | |
3030
| Drop module | `DROP MODULE ModuleName;` | |
31+
| Rename module | `RENAME MODULE OldName TO NewName;` | Updates all qualified name references |
3132

3233
## Domain Model
3334

@@ -40,6 +41,9 @@ CREATE PERSISTENT ENTITY Module.Photo (
4041
| Drop entity | `DROP ENTITY Module.Name;` | |
4142
| Describe entity | `DESCRIBE ENTITY Module.Name;` | Full MDL output |
4243
| Describe enumeration | `DESCRIBE ENUMERATION Module.Name;` | Full MDL output |
44+
| Rename entity | `RENAME ENTITY Module.Old TO New;` | Updates all references |
45+
| Rename enumeration | `RENAME ENUMERATION Module.Old TO New;` | Updates attribute type refs |
46+
| Rename association | `RENAME ASSOCIATION Module.Old TO New;` | Updates all references |
4347
| Show entities | `SHOW ENTITIES [IN Module];` | List all or filter by module |
4448
| Create enumeration | `CREATE [OR MODIFY] ENUMERATION Module.Name (Value1 'Caption', ...);` | |
4549
| Drop enumeration | `DROP ENUMERATION Module.Name;` | |
@@ -160,6 +164,10 @@ AUTHENTICATION Basic, Session
160164
| Show nanoflows | `SHOW NANOFLOWS [IN Module];` | List all or filter by module |
161165
| Describe microflow | `DESCRIBE MICROFLOW Module.Name;` | Full MDL with activities |
162166
| Describe nanoflow | `DESCRIBE NANOFLOW Module.Name;` | Full MDL with activities |
167+
| Rename microflow | `RENAME MICROFLOW Module.Old TO New;` | Updates all references |
168+
| Rename nanoflow | `RENAME NANOFLOW Module.Old TO New;` | Updates all references |
169+
| Rename page | `RENAME PAGE Module.Old TO New;` | Updates all references |
170+
| Rename constant | `RENAME CONSTANT Module.Old TO New;` | Updates all references |
163171
| Drop microflow | `DROP MICROFLOW Module.Name;` | |
164172
| Drop nanoflow | `DROP NANOFLOW Module.Name;` | |
165173

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
-- =============================================================================
2+
-- RENAME Examples
3+
-- =============================================================================
4+
5+
CREATE MODULE RenameTest;
6+
7+
-- Create test entities
8+
CREATE PERSISTENT ENTITY RenameTest.Customer (
9+
Name: String(200),
10+
Email: String(200)
11+
);
12+
13+
CREATE PERSISTENT ENTITY RenameTest.Order (
14+
OrderDate: DateTime
15+
);
16+
17+
CREATE ASSOCIATION RenameTest.Order_Customer
18+
FROM RenameTest.Order TO RenameTest.Customer
19+
TYPE Reference;
20+
21+
-- Rename entity
22+
RENAME ENTITY RenameTest.Customer TO Client;
23+
24+
-- Rename association
25+
RENAME ASSOCIATION RenameTest.Order_Customer TO Order_Client;
26+
27+
-- Clean up
28+
DROP ASSOCIATION RenameTest.Order_Client;
29+
DROP ENTITY RenameTest.Client;
30+
DROP ENTITY RenameTest.Order;

mdl/ast/ast_rename.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package ast
4+
5+
// RenameStmt represents:
6+
//
7+
// RENAME ENTITY Module.OldName TO NewName [DRY RUN];
8+
// RENAME MODULE OldName TO NewName [DRY RUN];
9+
type RenameStmt struct {
10+
ObjectType string // "ENTITY", "MODULE"
11+
Name QualifiedName // Current name (Module.Entity or Module for modules)
12+
NewName string // New simple name (just the name, not qualified)
13+
DryRun bool // If true, report references without modifying
14+
}
15+
16+
func (s *RenameStmt) isStatement() {}

0 commit comments

Comments
 (0)