Value Objects
Value Objects (VOs) are objects that matter only as the combination of their properties. Two Value Objects with the same values are considered equal.
In Carno.js ORM, Value Objects are first-class citizens. They encapsulate validation logic and can be used directly as entity properties.
Creating a Value Object
To create a custom Value Object, extend the abstract ValueObject<T, Vo> class. You must implement the validate method.
Example: Email VO
import { ValueObject } from '@carno.js/orm';
// <Type of raw value, The Class itself>
export class Email extends ValueObject<string, Email> {
// Optional: Define database constraints
protected max = 255;
protected validate(value: string): boolean {
// Return true if valid, false otherwise
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
}
}
Example: Age VO
import { ValueObject } from '@carno.js/orm';
export class Age extends ValueObject<number, Age> {
protected min = 0;
protected max = 150;
protected validate(value: number): boolean {
return Number.isInteger(value);
}
}
Using in Entities
Use the standard @Property() decorator. The ORM automatically detects that the type is a ValueObject and handles serialization/deserialization.
import { Entity, Property, BaseEntity } from '@carno.js/orm';
import { Email } from './values/email.vo';
import { Age } from './values/age.vo';
@Entity()
export class User extends BaseEntity {
@Property()
email: Email;
@Property()
age: Age;
}
Creating Instances
Value Objects enforce validation upon instantiation. If the value is invalid, it throws an HttpException (Status 400).
// Valid
const email = new Email('user@example.com');
console.log(email.getValue()); // 'user@example.com'
// Factory method
const age = Age.from(25);
// Invalid - Throws Error
const invalid = new Email('not-an-email');
Database Mapping
When saving to the database:
- The ORM calls
.getValue()to extract the raw primitive (string, number, etc.). - That raw value is stored in the column.
When loading from the database:
- The ORM instantiates the Value Object with the raw value from the column.
- Validation runs again (ensuring data integrity).
Built-in Constraints
The ValueObject class supports declarative constraints that are checked during instantiation:
max: Max length (string) or max value (number).min: Min length (string) or min value (number).precision: Total digits (for numbers).scale: Decimal digits (for numbers).
If these are set in the class, they are also used to configure the database column definition (e.g., VARCHAR(255) if max = 255).