Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .claude/skills/fix-issue.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ to the symptom table below, so the next similar issue costs fewer reads.
| CE0463 "widget definition changed" on every pluggable widget that contains a caption/template parameter (gallery, datagrid2 captions, dynamictext with ContentParams) on Mendix 11.9 — cascades into CE3637 on master-detail pages | `serializeClientTemplateParameter` emitted `Forms$FormattingInfo` with a `TimeFormat: "HoursMinutes"` field, but the FormattingInfo reflection schema only declares CustomDateFormat / DateFormat / DecimalPrecision / EnumFormat / GroupDigits — the extra field made Studio Pro mark the embedded WidgetType as drifted | `sdk/mpr/writer_widgets.go` `serializeClientTemplateParameter` + `mdl/backend/mpr/widget_builder.go` (mirror copy of the same FormattingInfo block) | Drop the `TimeFormat` entry from both writers. Verify by diffing your BSON against a Studio Pro-saved page's FormattingInfo block — if you see keys outside the reflection schema, that's the trigger |
| Pluggable widget `Selection` BSON value is lowercase (`single` / `multi` / `none`) but Studio Pro stores PascalCase — contributes to CE0463 drift on stricter widgets and looks wrong in diffs | MDL passes the user's typed value verbatim to `SetSelection`; the builder didn't normalise | `mdl/backend/mpr/widget_builder.go` `SetSelection` | Canonicalise via `canonicalSelectionValue` helper (lowercase-keyed switch → `Single` / `Multi` / `None`); unknown values pass through |
| Nightly `mx check` reports `CE0117 "Error(s) in expression." at Log message activity 'Log message (warning)'` on Mendix 10.24.19+ but not 10.24.16 or 11.x | Mendix 10.24.19 tightened expression validation: `toString(<string>)` is now a type error (toString expects a non-string input). An example called `toString($OrderNumber)` where `$OrderNumber` was already a string parameter | The offending `log warning ... with ({1} = toString($stringVar))` — find via `~/.mxcli/mxbuild/{ver}/modeler/mx check`, then bisect with `drop microflow ...` until CE0117 disappears | Remove the redundant `toString()` wrapper around already-string values. Only wrap non-string values (integers, decimals, dates, enums) in `toString()`. The Mendix 11.x parser is more lenient and lets this slide, but 10.24.19+ rejects it |
| `describe entity` shows every String attribute as `String(unlimited)` and `CATALOG.ATTRIBUTES.Length` reports `0` for all of them, even though Studio Pro shows a finite max length and runtime rejects overlong values | BSON numeric width mismatch — Mendix Studio Pro stores `Length` as int64, but `parseAttributeType` used `raw["Length"].(int32)` so the assertion always failed and Length defaulted to 0 | `sdk/mpr/parser_domainmodel.go` → `parseAttributeType` `case "DomainModels$StringAttributeType"` | Replace narrow type assertions on BSON numeric fields with the existing `extractInt(raw["X"])` helper (`sdk/mpr/parser.go`), which handles int32/int64/int/float64. Sweep other `parser_*.go` files for the same `.(int32)` / `.(int64)` pattern on size/length/count fields. Issue #583 |

---

Expand Down
28 changes: 28 additions & 0 deletions mdl-examples/bug-tests/583-string-attribute-length-roundtrip.mdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-- Bug test: String attribute length must roundtrip through write -> read -> describe.
-- Issue #583: describe entity and CATALOG.ATTRIBUTES reported every String attribute
-- as String(unlimited) / Length: 0, even when a finite length was set. Root cause was
-- a type assertion in sdk/mpr/parser_domainmodel.go that only accepted BSON int32,
-- while Mendix Studio Pro stores the Length field as BSON int64.
--
-- The Go unit test in sdk/mpr/parser_domainmodel_test.go reproduces the original
-- int64-from-Studio-Pro decode path. This MDL script is a complementary end-to-end
-- regression test: it creates entities with several finite lengths plus one unlimited
-- string, then asserts that describe emits the expected lengths back.
--
-- Run with:
-- mxcli exec mdl-examples/bug-tests/583-string-attribute-length-roundtrip.mdl
-- mxcli check mdl-examples/bug-tests/583-string-attribute-length-roundtrip.mdl
create module bug583;

create persistent entity bug583.Item (
ShortCode: string(10),
Description: string(200),
LongText: string(4000),
Notes: string
);

describe entity bug583.Item;

select Name, DataType, Length from CATALOG.ATTRIBUTES
where EntityQualifiedName = 'bug583.Item'
order by Name;
6 changes: 3 additions & 3 deletions sdk/mpr/parser_domainmodel.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,9 +360,9 @@ func parseAttributeType(raw map[string]any) domainmodel.AttributeType {
case "DomainModels$StringAttributeType":
t := &domainmodel.StringAttributeType{}
t.ID = typeID
if length, ok := raw["Length"].(int32); ok {
t.Length = int(length)
}
// Issue #583: Studio Pro stores Length as BSON int64; mxcli's writer
// emits int32. extractInt accepts both (plus int and float64).
t.Length = extractInt(raw["Length"])
return t
case "DomainModels$IntegerAttributeType":
t := &domainmodel.IntegerAttributeType{}
Expand Down
48 changes: 48 additions & 0 deletions sdk/mpr/parser_domainmodel_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// SPDX-License-Identifier: Apache-2.0

package mpr

import (
"testing"

"github.com/mendixlabs/mxcli/sdk/domainmodel"
)

// Issue #583: parseAttributeType silently dropped the Length value for
// StringAttributeType when Mendix Studio Pro stored it as BSON int64.
// The previous code only handled int32, so every String attribute in a
// Studio Pro-written MPR was reported as String(unlimited) / Length: 0.
//
// Studio Pro and mxcli can both store integers as int32 or int64 depending
// on encoder choice; the parser must handle every BSON numeric width.
func TestParseAttributeType_StringLength_BsonNumericWidths(t *testing.T) {
cases := []struct {
name string
length any
want int
}{
{"int32 (mxcli writer)", int32(40), 40},
{"int64 (Studio Pro writer)", int64(40), 40},
{"int", int(40), 40},
{"float64 (extended JSON)", float64(40), 40},
{"missing field = unlimited", nil, 0},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
raw := map[string]any{
"$Type": "DomainModels$StringAttributeType",
}
if tc.length != nil {
raw["Length"] = tc.length
}
at := parseAttributeType(raw)
st, ok := at.(*domainmodel.StringAttributeType)
if !ok {
t.Fatalf("parseAttributeType returned %T, want *StringAttributeType", at)
}
if st.Length != tc.want {
t.Errorf("Length = %d, want %d (input %T(%v))", st.Length, tc.want, tc.length, tc.length)
}
})
}
}
Loading