Skip to content

modelsdk codec writes Integer fields (canvas/popup dimensions) as BSON int32, not int64 #675

@ako

Description

@ako

Summary

The modelsdk codec engine serializes Mendix Integer properties as BSON int32, but Studio Pro (and the legacy MPR writer) store these as int64. The mismatch is tolerated by mx check today, but it produces type-inconsistent BSON: codec-written pages differ from Studio-Pro-written pages, and within a single page the CREATE path (codec, int32) disagrees with the page-mutator ALTER path (raw BSON, int64).

Surfaced while implementing pop-up dimensions for #661 — the codec write path was the one place that couldn't match Studio Pro's on-disk type.

Evidence

Fresh 11.11.0 project, two pages created via mxcli, dumped with mxcli bson dump --format bson:

Field Studio Pro / legacy writer modelsdk codec
CanvasWidth / CanvasHeight int64 int32
PopupWidth / PopupHeight int64 int32

Both pass mx check (0 errors), so this is correctness/consistency hygiene, not a build break.

Root cause

modelsdk/property/primitive.goBSONValue() returns Get(), so a Primitive[int32] serializes as int32:

func (p *Primitive[T]) BSONValue() any { return p.Get() }

The gen types bind these fields as int32 (engalar's generator maps reflection Integerint32), e.g. modelsdk/gen/pages/types.go:

o.canvasWidth = property.NewPrimitive[int32]("CanvasWidth", property.DecodeInt32)
o.popupWidth  = property.NewPrimitive[int32]("PopupWidth",  property.DecodeInt32)

The read side already knows the truth — property.DecodeInt32's own doc comment:

Mendix/Studio Pro stores small integers (connection indices, canvas positions, …) as BSON int64 — and occasionally as double — not int32, so accept all three numeric encodings.

So the decoder tolerates int64 on read; only the encoder emits the wrong width. This is the same gen storage concern noted previously for canvas/popup.

Scope / blast radius

This affects every Integer-typed gen field across all document types (canvas/popup dimensions, microflow connection indices, positions, etc.) — not just pages. That breadth is exactly why it was kept out of the #661 PR.

Options

  1. Encoder-level (broadest, cleanest): make Primitive[int32].BSONValue() emit int64. Aligns all Integer fields with Studio Pro in one place; the decoder already round-trips int64. Needs validation that no consumer/round-trip test asserts int32 on the serialized side.
  2. Codegen type mapping: map reflection Integer → an int64-emitting primitive in engalar's generator and regenerate modelsdk/gen/**. More faithful to the metamodel but touches the generator toolchain.
  3. Per-field override: force int64 for a known list of dimension fields only. Narrowest, but a manually-maintained list (maintenance risk) and leaves other Integer fields inconsistent.

Recommend option 1 or 2 (whole-class fix) over 3.

Acceptance

  • modelsdk codec writes Integer fields as BSON int64 (canvas + popup at minimum).
  • A codec-created page's CanvasWidth/PopupWidth BSON type matches a Studio-Pro-authored page byte-for-type.
  • CREATE (codec) and ALTER (mutator) produce the same type for popup dimensions.
  • mx check stays green across doc types; round-trip tests updated for int64.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions