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')