Skip to content

Commit 74f0425

Browse files
akoclaude
andcommitted
Fix quoted identifiers in enum DEFAULT values causing CE1613
Strip surrounding quotes from each segment of dotted qualified names in DEFAULT value expressions. Previously, `expr.GetText()` preserved raw quotes (e.g. MaisonElegance."FormSubmissionStatus".StatusNew), producing invalid enum references that MxBuild could not resolve. Fixes #11 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d522e2a commit 74f0425

2 files changed

Lines changed: 82 additions & 2 deletions

File tree

mdl/visitor/visitor_helpers.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ func unquoteIdentifier(s string) string {
2222
return s
2323
}
2424

25+
// unquoteQualifiedName strips quotes from each segment of a dotted qualified name.
26+
// e.g. MaisonElegance."FormSubmissionStatus".StatusNew -> MaisonElegance.FormSubmissionStatus.StatusNew
27+
func unquoteQualifiedName(s string) string {
28+
parts := strings.Split(s, ".")
29+
for i, p := range parts {
30+
parts[i] = unquoteIdentifier(p)
31+
}
32+
return strings.Join(parts, ".")
33+
}
34+
2535
// attributeNameText extracts the clean name from an AttributeNameContext,
2636
// stripping quotes from QUOTED_IDENTIFIER tokens.
2737
func attributeNameText(ctx parser.IAttributeNameContext) string {
@@ -196,7 +206,7 @@ func buildAttributes(ctx parser.IAttributeDefinitionListContext, b *Builder) []a
196206
if lit := c.Literal(); lit != nil {
197207
attr.DefaultValue = extractLiteralValue(lit)
198208
} else if expr := c.Expression(); expr != nil {
199-
attr.DefaultValue = expr.GetText()
209+
attr.DefaultValue = unquoteQualifiedName(expr.GetText())
200210
}
201211
}
202212
if c.REQUIRED() != nil {
@@ -248,7 +258,7 @@ func buildSingleAttribute(a *parser.AttributeDefinitionContext) *ast.Attribute {
248258
if lit := c.Literal(); lit != nil {
249259
attr.DefaultValue = extractLiteralValue(lit)
250260
} else if expr := c.Expression(); expr != nil {
251-
attr.DefaultValue = expr.GetText()
261+
attr.DefaultValue = unquoteQualifiedName(expr.GetText())
252262
}
253263
}
254264
if c.REQUIRED() != nil {

mdl/visitor/visitor_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
package visitor
44

55
import (
6+
"fmt"
67
"strings"
78
"testing"
89

@@ -1110,6 +1111,75 @@ END;`
11101111
}
11111112
}
11121113

1114+
// TestEnumDefaultQuotedIdentifier verifies that quoted identifiers in enum
1115+
// DEFAULT values are unquoted correctly (issue #11 / BUG-004).
1116+
// e.g. DEFAULT MaisonElegance."FormSubmissionStatus".StatusNew should store
1117+
// MaisonElegance.FormSubmissionStatus.StatusNew (quotes stripped).
1118+
func TestEnumDefaultQuotedIdentifier(t *testing.T) {
1119+
tests := []struct {
1120+
name string
1121+
input string
1122+
wantDflt string
1123+
}{
1124+
{
1125+
name: "quoted enum name in DEFAULT",
1126+
input: `CREATE PERSISTENT ENTITY MaisonElegance.FormSubmission (
1127+
SubmissionStatus: Enumeration(MaisonElegance."FormSubmissionStatus") DEFAULT MaisonElegance."FormSubmissionStatus".StatusNew
1128+
);`,
1129+
wantDflt: "MaisonElegance.FormSubmissionStatus.StatusNew",
1130+
},
1131+
{
1132+
name: "unquoted enum name in DEFAULT (unchanged)",
1133+
input: `CREATE PERSISTENT ENTITY MaisonElegance.FormSubmission (
1134+
SubmissionStatus: Enumeration(MaisonElegance.FormSubmissionStatus) DEFAULT MaisonElegance.FormSubmissionStatus.StatusNew
1135+
);`,
1136+
wantDflt: "MaisonElegance.FormSubmissionStatus.StatusNew",
1137+
},
1138+
{
1139+
name: "backtick-quoted enum name in DEFAULT",
1140+
input: "CREATE PERSISTENT ENTITY Test.MyEntity (\n" +
1141+
"\tStatus: Enumeration(Test.`MyEnum`) DEFAULT Test.`MyEnum`.Active\n" +
1142+
");",
1143+
wantDflt: "Test.MyEnum.Active",
1144+
},
1145+
}
1146+
1147+
for _, tt := range tests {
1148+
t.Run(tt.name, func(t *testing.T) {
1149+
prog, errs := Build(tt.input)
1150+
if len(errs) > 0 {
1151+
for _, err := range errs {
1152+
t.Errorf("Parse error: %v", err)
1153+
}
1154+
return
1155+
}
1156+
1157+
if len(prog.Statements) != 1 {
1158+
t.Fatalf("Expected 1 statement, got %d", len(prog.Statements))
1159+
}
1160+
1161+
stmt, ok := prog.Statements[0].(*ast.CreateEntityStmt)
1162+
if !ok {
1163+
t.Fatalf("Expected CreateEntityStmt, got %T", prog.Statements[0])
1164+
}
1165+
1166+
if len(stmt.Attributes) != 1 {
1167+
t.Fatalf("Expected 1 attribute, got %d", len(stmt.Attributes))
1168+
}
1169+
1170+
attr := stmt.Attributes[0]
1171+
if !attr.HasDefault {
1172+
t.Fatal("Expected HasDefault to be true")
1173+
}
1174+
1175+
got := fmt.Sprintf("%v", attr.DefaultValue)
1176+
if got != tt.wantDflt {
1177+
t.Errorf("DefaultValue = %q, want %q", got, tt.wantDflt)
1178+
}
1179+
})
1180+
}
1181+
}
1182+
11131183
func TestSQLGenerateConnector(t *testing.T) {
11141184
tests := []struct {
11151185
name string

0 commit comments

Comments
 (0)