sea-orm icon indicating copy to clipboard operation
sea-orm copied to clipboard

Proposal: type safe column expr methods

Open Huliiiiii opened this issue 2 months ago • 2 comments

Background

Currently, we represents database columns using a Column enum (e.g., Column::Id, Column::Name).

However, this approach has a limitation for compile-time type safety.

All variants of the Column enumeration share the same type ( Column ), which means that it is not possible to directly attach Rust data types (e.g. i32 , String ) to a single column variant itself.

So, I think we can add a TypedColumn struct:

struct TypedColumn<C, Type>
where
    C: ColumnTrait
    Type: Into<ValueType>
{
    col: C,
    ty: PhantomData<Type>
}

With TypedColumn, we can then implement methods that are specific to the column's data type. For example:

impl<C, T> TypedColumn<C, T> { 
    // another new trait for type safty
    pub fn eq<T2: ValueOrExpr<T>>(&self, value: T2) -> Expr {
        self.col.eq(value.into())
    }
}


impl<C> TypedColumn<C, String> {
    pub fn ilike<T: ValueOrExpr<String>>(&self, value: T) -> Expr {
        self.col.ilike(value.into())
    }
}

And we can generate TypedColumn constructors in codegen:

impl Entity {
    pub fn id() -> TypedColumn<Column, i32> {
        TypedColumn {
            col: Column::Id,
            ty: PhantomData,
        }
    }

    pub fn name() -> TypedColumn<Column, String> {
        TypedColumn {
            col: Column::Name,
            ty: PhantomData,
        }
    }
}

Benefits

  • Compile-time type safety

Considerations

As I've rarely encountered type mismatch errors in my own sea-orm usage (perhaps due to careful query construction), I'm unsure how many others would significantly benefit from this feature.

Duplication

Methods implemented on TypedColumn<C, Type> would largely mirror identical methods already presenton ExprTrait. This creates a duplicate API surface for essentially the same underlying functionality.

Maintenance Burden

Conceptually, any new expression method introduced on ExprTrait would need to be implemented in all relevant impl TypedColumn<C, Type> blocks to maintain full type-safety coverage, which would increase the maintenance burden.

Huliiiiii avatar Oct 19 '25 15:10 Huliiiiii

If TypedColumn can be Into<SimpleExpr> wouldn't that come for nearly free?

lu-zero avatar Oct 20 '25 14:10 lu-zero

If TypedColumn can be Into<SimpleExpr> wouldn't that come for nearly free?

I think it's zero overhead.

But one problem is that we implement ExprTrait for T: Into<Expr>, which will result in ExprTrait::eq being called instead of TypedColum::eq in some cases.

Huliiiiii avatar Oct 20 '25 15:10 Huliiiiii