Skip to content

Fix enum-backed integer columns annotations - #380

Open
dmke wants to merge 2 commits into
drwl:mainfrom
dmke:fix/373
Open

Fix enum-backed integer columns annotations#380
dmke wants to merge 2 commits into
drwl:mainfrom
dmke:fix/373

Conversation

@dmke

@dmke dmke commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

This PR contains two changes, feel free to omit the latter if not desired.


Part 1: Detect attribute default overrides by raw value

Restores enum-backed defaults in annotations. Reverts to default("idnow") instead of the raw default(0) emitted since v4.24.0.

Fixes #373.

Part 2: Add enum_default_format option

Make the default shown for enum-backed columns configurable, via enum_default_format or --enum-default-format:

default("idnow")      # label (default)
default(0)            # raw
default(0: "idnow")   # both

label keeps the historical output.

dmke added 2 commits August 10, 2026 20:31
## Summary

Restore enum-backed defaults in annotations: `default("idnow")` instead
of the raw `default(0)` emitted since v4.24.0. Fixes drwl#373.

## Motivation

drwl#358 detects `attribute :foo, default: X` overrides by comparing
`Model#column_defaults[name]` against `column.default` deserialized
through the schema-level cast type. That comparison casts the same raw
default through two different type systems, so any decorated attribute
type looks like an override: an enum casts the DB default `0` into its
label, the schema type casts it into `0`, the values differ, and the
schema value wins. Enum columns are the visible case, but every
decorated type is affected.

## Changes

Compare the raw, pre-cast values instead. Rails builds default
attributes with `Attribute.from_database(column.name, column.default,
type)`, so `_default_attributes[name].value_before_type_cast` is
`column.default` itself unless `attribute :foo, default: X` replaced it
with a `UserProvidedDefault`. Type decoration goes through `with_type`,
which preserves the raw value. No casting involved, so the check is
exact for both cases.

The test doubles gain `_default_attributes` to mirror that structure.
## Summary

Make the default shown for enum backed columns configurable, via
`enum_default_format` or `--enum-default-format`:

    default("idnow")      # label (default)
    default(0)            # raw
    default(0: "idnow")   # both

`label` keeps the historical output. Relates to drwl#373.

## Motivation

The label is the meaningful value for most readers, but it hides the
integer that is actually stored, which matters when reading queries or
raw data. Neither representation is right for everyone, so let the user
pick.

## Changes

`ModelWrapper#column_defaults` knows both values already: the label from
`Model#column_defaults` and the raw one from the schema cast type. It
now picks between them for columns listed in `defined_enums`.

The `both` format needs to carry two values down to the annotation, so
it passes an `EnumDefault` struct that `DefaultValueBuilder` renders by
quoting each half. Going through `Hash#inspect` instead would make the
output depend on the Ruby version.

String backed enums fall through to the label in every format, since
their raw value is the label.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4.24.0: enum-backed integer columns annotate raw default(0) instead of default("label")

2 participants