Custom Value Types
Relevant source files
The following files were used as context for generating this wiki page:
Custom Value Types in SeaORM allow developers to define domain-specific Rust types that wrap standard database types while maintaining full integration with the ORM's querying and persistence layers. This feature provides compile-time type safety for database columns by allowing the use of newtypes or specialized structs instead of primitive types.
In SeaORM 2.0, this is primarily achieved through the DeriveValueType macro, which automatically handles the conversion between the custom Rust type and the underlying sea_query::Value. The system is designed to be ergonomic, requiring minimal configuration as SeaORM typically infers the required database column type from the inner type of the wrapper.
Sources: CLAUDE.md:129-141, tests/value_type_tests.rs:94-118
Core Implementation and Macros
The primary mechanism for creating a custom value type is the #[derive(DeriveValueType)] macro. This macro implements the necessary traits to allow a struct to be used as a column type in an Entity Model.
Auto-generated Traits
When a struct derives ValueType, the macro auto-generates several internal implementations:
NotU8: A marker trait used for internal type specialization.IntoActiveValue: Enables the type to be converted into an active value for database operations.TryFromU64: Provides basic numeric conversion support where applicable.
Sources: CLAUDE.md:173-176
Type Mapping and Metadata
Custom value types expose metadata through the ValueType trait, including the type name and the associated database column types.
| Method | Description | Example Output |
|---|---|---|
type_name() | Returns the string name of the Rust type. | "MyInteger" |
column_type() | Returns the sea_query::ColumnType the type maps to. | ColumnType::Integer |
array_type() | Returns the sea_query::ArrayType for PostgreSQL arrays. | ArrayType::Int |
Sources: tests/value_type_tests.rs:94-102, sea-orm-sync/tests/value_type_tests.rs:94-102
Data Flow and Conversion
Custom value types act as a bridge between the Rust application layer and the SeaQuery value layer. The flow involves wrapping a primitive or complex type and providing safe conversion paths.
Conversion Logic
This diagram shows the transformation of a custom type into a generic Value for database interaction and the fallible conversion back into the custom type.
Sources: tests/value_type_tests.rs:121-135
Validation and Errors
Conversion from a database value to a custom type is fallible. If a database row returns a type incompatible with the custom type's definition, SeaORM returns a ValueTypeErr. For example, attempting to convert a Value::Char into a custom StringVec type will result in a conversion error.
Sources: tests/value_type_tests.rs:134-136
Integration with Entities
Custom value types are used directly as field types within an entity's Model struct. The SeaORM macros handle the registration of these types within the Column enum.
Entity Model Usage
When defining an entity, custom types are assigned to fields. The #[sea_orm::model] macro and DeriveEntityModel macro detect these types and map them to the corresponding database columns.
#[derive(Clone, Debug, PartialEq, DeriveValueType)]
pub struct Speed(Decimal);
#[sea_orm::model]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub speed: Speed, // SeaORM infers Decimal column type automatically
}
Sources: CLAUDE.md:131-141
Type Inference and Annotations
A critical guideline in SeaORM 2.0 is to avoid redundant column_type annotations on custom wrapper types. Because DeriveValueType maps the custom type to its inner type, SeaORM's codegen and macro system already know the correct database type.
Sources: CLAUDE.md:131-137, sea-orm-macros/src/derives/entity_model.rs:252-259
Typed Columns
The TypedColumn system in SeaORM 2.0 provides compile-time safety for filters and expressions. When a custom type is used, the expand_typed_column logic wraps the standard Column variant in a type-safe wrapper if a specific mapping is required.
Sources: sea-orm-macros/src/derives/typed_column.rs:72-88
Usage in Primary Keys
Custom value types can also be used as primary keys. This is useful for implementing domain-specific identifiers (e.g., UserId(u64)).
This sequence illustrates how custom types function throughout the lifecycle of a record, from insertion to retrieval by ID.
Sources: tests/value_type_tests.rs:60-77
Primary Key Trait Integration
When a custom type is used as a primary key, the PrimaryKeyTrait implementation generated by SeaORM uses the custom type as its ValueType. The ORM handles the underlying conversion to ensure the database receives the raw value during lookups.
Sources: sea-orm-macros/src/derives/entity_model.rs:430-440
Conclusion
Custom Value Types provide a robust way to enforce domain logic at the type level within SeaORM. By leveraging the DeriveValueType macro, developers can create type-safe wrappers for database columns that integrate seamlessly with the ORM's ActiveModel and Querying APIs, ensuring that business logic is reflected in the data access layer without sacrificing the convenience of an ORM.
Sources: CLAUDE.md:129-141, tests/value_type_tests.rs:94-118