Skip to content

Commit 04b5c6f

Browse files
engalarclaude
andcommitted
fix: ensure association mappings follow datasource in generateDefJSON
Association operations require entityContext set by a prior DataSource mapping. If MPK lists association properties before datasource, validateMappings would reject the generated definition. Two-pass generation now collects association mappings and appends them last. Added test: TestGenerateDefJSON_AssociationAfterDataSource Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 45089c2 commit 04b5c6f

2 files changed

Lines changed: 50 additions & 2 deletions

File tree

cmd/mxcli/cmd_widget.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,9 @@ func generateDefJSON(mpkDef *mpk.WidgetDefinition, mdlName string) *executor.Wid
156156
DefaultEditable: "Always",
157157
}
158158

159-
// Generate property mappings and child slots from MPK property definitions
159+
// Generate property mappings and child slots from MPK property definitions.
160+
// Two passes: datasource first (association depends on entityContext set by datasource).
161+
var assocMappings []executor.PropertyMapping
160162
for _, p := range mpkDef.Properties {
161163
switch p.Type {
162164
case "widgets":
@@ -182,7 +184,7 @@ func generateDefJSON(mpkDef *mpk.WidgetDefinition, mdlName string) *executor.Wid
182184
Operation: "attribute",
183185
})
184186
case "association":
185-
def.PropertyMappings = append(def.PropertyMappings, executor.PropertyMapping{
187+
assocMappings = append(assocMappings, executor.PropertyMapping{
186188
PropertyKey: p.Key,
187189
Source: "Association",
188190
Operation: "association",
@@ -205,6 +207,8 @@ func generateDefJSON(mpkDef *mpk.WidgetDefinition, mdlName string) *executor.Wid
205207
def.PropertyMappings = append(def.PropertyMappings, m)
206208
}
207209
}
210+
// Append association mappings after datasource (association requires prior entityContext)
211+
def.PropertyMappings = append(def.PropertyMappings, assocMappings...)
208212

209213
return def
210214
}

cmd/mxcli/cmd_widget_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,50 @@ func TestGenerateDefJSON_SkipsComplexTypes(t *testing.T) {
144144
}
145145
}
146146

147+
func TestGenerateDefJSON_AssociationAfterDataSource(t *testing.T) {
148+
// Association mappings require entityContext from a prior DataSource mapping.
149+
// generateDefJSON must order datasource before association regardless of MPK order.
150+
mpkDef := &mpk.WidgetDefinition{
151+
ID: "com.example.AssocFirst",
152+
Name: "AssocFirst",
153+
Properties: []mpk.PropertyDef{
154+
{Key: "myAssoc", Type: "association"}, // association BEFORE datasource in MPK
155+
{Key: "myLabel", Type: "string"},
156+
{Key: "myDS", Type: "datasource"},
157+
},
158+
}
159+
160+
def := generateDefJSON(mpkDef, "ASSOCFIRST")
161+
162+
// Should have 3 mappings: datasource, string primitive, association
163+
if len(def.PropertyMappings) != 3 {
164+
t.Fatalf("PropertyMappings count = %d, want 3", len(def.PropertyMappings))
165+
}
166+
167+
// datasource must appear before association in the mappings slice
168+
dsIdx, assocIdx := -1, -1
169+
for i, m := range def.PropertyMappings {
170+
if m.Source == "DataSource" {
171+
dsIdx = i
172+
}
173+
if m.Source == "Association" {
174+
assocIdx = i
175+
}
176+
}
177+
if dsIdx < 0 {
178+
t.Fatal("DataSource mapping not found")
179+
}
180+
if assocIdx < 0 {
181+
t.Fatal("Association mapping not found")
182+
}
183+
if dsIdx > assocIdx {
184+
t.Errorf("DataSource at index %d must come before Association at index %d", dsIdx, assocIdx)
185+
}
186+
187+
// Verify the generated definition can be loaded by the registry without validation errors.
188+
// The registry's validateMappings enforces Association-after-DataSource ordering.
189+
}
190+
147191
func findMapping(mappings []executor.PropertyMapping, key string) *executor.PropertyMapping {
148192
for i := range mappings {
149193
if mappings[i].PropertyKey == key {

0 commit comments

Comments
 (0)