Skip to content

Commit b03fa6a

Browse files
akoclaude
andcommitted
fix: auto-convert non-String ContentParams to toString() expressions
When a DYNAMICTEXT ContentParams binding references a non-String attribute (Integer, Decimal, DateTime, Boolean), automatically emit a toString() expression instead of a direct AttributeRef. This prevents pages from rendering incorrectly at runtime. Before: ContentParams: [{1} = TotalOrders] → AttributeRef (broken) After: ContentParams: [{1} = TotalOrders] → toString($currentObject/TotalOrders) String attributes continue to use direct AttributeRef as before. Type detection uses the existing findAttributeType() infrastructure and fails open (if type can't be determined, assumes String). Closes #146 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 3b022f5 commit b03fa6a

File tree

1 file changed

+36
-5
lines changed

1 file changed

+36
-5
lines changed

mdl/executor/cmd_pages_builder_v3.go

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
"github.com/mendixlabs/mxcli/mdl/ast"
1010
"github.com/mendixlabs/mxcli/model"
11+
"github.com/mendixlabs/mxcli/sdk/domainmodel"
1112
"github.com/mendixlabs/mxcli/sdk/microflows"
1213
"github.com/mendixlabs/mxcli/sdk/mpr"
1314
"github.com/mendixlabs/mxcli/sdk/pages"
@@ -1143,6 +1144,10 @@ func (pb *pageBuilder) resolveTemplateAttributePath(attrRef string) string {
11431144
//
11441145
// When attrRef is $paramName.Attribute (where paramName is a page/snippet parameter),
11451146
// it sets SourceVariable to paramName and AttributeRef to the resolved entity path.
1147+
//
1148+
// For non-String attributes (Integer, Decimal, DateTime, Boolean, etc.), the binding
1149+
// is automatically converted to a toString() expression since DYNAMICTEXT template
1150+
// parameters require String values.
11461151
func (pb *pageBuilder) resolveTemplateAttributePathFull(attrRef string, param *pages.ClientTemplateParameter) {
11471152
if attrRef == "" {
11481153
return
@@ -1158,22 +1163,48 @@ func (pb *pageBuilder) resolveTemplateAttributePathFull(attrRef string, param *p
11581163

11591164
// Check if this is a page/snippet parameter (not a widget reference)
11601165
if entityName, ok := pb.paramEntityNames[paramName]; ok {
1161-
// This is a page parameter reference
1166+
fullPath := entityName + "." + attrName
1167+
if pb.isNonStringAttribute(fullPath) {
1168+
param.Expression = "toString($" + paramName + "/" + attrName + ")"
1169+
return
1170+
}
11621171
param.SourceVariable = paramName
1163-
param.AttributeRef = entityName + "." + attrName
1172+
param.AttributeRef = fullPath
11641173
return
11651174
}
11661175
// Try with $ prefix (for snippet parameters)
11671176
if entityName, ok := pb.paramEntityNames["$"+paramName]; ok {
1177+
fullPath := entityName + "." + attrName
1178+
if pb.isNonStringAttribute(fullPath) {
1179+
param.Expression = "toString($" + paramName + "/" + attrName + ")"
1180+
return
1181+
}
11681182
param.SourceVariable = paramName
1169-
param.AttributeRef = entityName + "." + attrName
1183+
param.AttributeRef = fullPath
11701184
return
11711185
}
11721186
}
11731187
}
11741188

1175-
// For other patterns, just set AttributeRef
1176-
param.AttributeRef = pb.resolveTemplateAttributePath(attrRef)
1189+
// For other patterns, resolve and check type
1190+
resolved := pb.resolveTemplateAttributePath(attrRef)
1191+
if pb.isNonStringAttribute(resolved) {
1192+
// Convert to toString() expression for non-String attributes
1193+
param.Expression = "toString($currentObject/" + attrRef + ")"
1194+
return
1195+
}
1196+
param.AttributeRef = resolved
1197+
}
1198+
1199+
// isNonStringAttribute checks if an attribute path refers to a non-String type.
1200+
// Returns false if the type can't be determined (fail-open to preserve existing behavior).
1201+
func (pb *pageBuilder) isNonStringAttribute(attrPath string) bool {
1202+
attrType := pb.findAttributeType(attrPath)
1203+
if attrType == nil {
1204+
return false // can't determine type, assume String
1205+
}
1206+
_, isString := attrType.(*domainmodel.StringAttributeType)
1207+
return !isString
11771208
}
11781209

11791210
// ============================================================================

0 commit comments

Comments
 (0)