Skip to main content

attributes

Attributes are usually set as part of create or update calls, or directly using dot notation (balloon.color = 'red' and then calling balloon.save); however, there are times (e.g. when adding custom getters and setters that transform the data prior to persisting) when it is helpful to bypass the getters and setters.

Decimal columns

PostgreSQL numeric/decimal columns return JavaScript number — not string or a Decimal wrapper. Dream's type-sync converts these to TypeScript number, so DreamColumn<Place, 'latitude'> resolves to number | null (or number if NOT NULL). No Number(value) coercion is needed when reading.

To control how many decimal places appear in a response, use the precision option on the serializer attribute rather than rounding in application code. This keeps the OpenAPI shape and rendered output consistent:

// In your serializer
.attribute('latitude', { precision: 7 })
.attribute('price', { precision: 2 })
// Also works on delegatedAttribute
.delegatedAttribute('place', 'latitude', { precision: 7 })

This handles the common floating-point quirk where 1.1 + 2.2 becomes 3.3000000000000003 — a value that rounds cleanly to 3.30 at the precision the schema actually cares about.

Branching on enum values

When branching on a database enum column, always use an exhaustive switch with a const _never: never default — never an if/else if chain. Database enums regenerated into @src/types/db.js are closed sets: an if/else if chain silently no-ops when a new enum value is added, while the _never default turns a missing case into a compile error.

const style = place.style // e.g. PlaceStylesEnum
switch (style) {
case 'cabin':
return handleCabin(place)
case 'cottage':
return handleCottage(place)
case 'apartment':
return handleApartment(place)
default: {
const _never: never = style
throw new Error(`Unhandled style: ${String(_never)}`)
}
}

This rule applies to any closed union of string literals: database enums, STI type discriminators, or any other union declared in code.

Bypassing methods

getAttributes

Returns an object containing all the columns on this Dream class, as well as their values, bypassing getters:

const user = User.new({ email: 'how@yadoin' })
user.getAttributes()
// {
// email: 'how@yadoin',
// ...
// }

getAttribute

Returns the value for a columnName provided, bypassing the getters:

const user = User.new({ email: 'how@yadoin' })
user.getAttribute('email')
// 'how@yadoin'

setAttributes

Takes the attributes passed in and sets their values internally, bypassing custom setters defined for these attributes:

const user = new User()
user.setAttributes({ email: 'my@email', password: 'my password' })

setAttribute

Changes the attribute value for a single attribute internally, bypassing custom-defined setters:

const user = new User()
user.setAttribute('email', 'sally@gmail.com')

Non-bypassing methods

assignAttributes

Takes the attributes passed in and sets their values, leveraging custom setters defined for these attributes:

const user = new User()
user.assignAttributes({ email: 'my@email', password: 'my password' })

assignAttribute

Changes the attribute value for a single attribute, leveraging custom-defined setters.

const user = new User()
user.assignAttribute('email', 'sally@gmail.com')