如何在过滤后移除Diesel中列的Nullable包装器?
问题:Diesel中过滤非空Nullable字段后如何直接获取非Option类型?
场景重现
1. Schema定义
table! { Foo (id) { id -> Integer, label -> Nullable<Text>, } }
2. 查询代码
let result: String = foo_dsl::Foo .select(foo_dsl::label) .filter(foo_dsl::label.is_not_null()) .first(&conn) .unwrap();
3. 错误信息
error[E0277]: the trait bound `*const str: FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, Mysql>` is not satisfied --> src/main.rs:21:10 | 21 | .first(&conn) | ^^^^^ the trait `FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, Mysql>` is not implemented for `*const str` | = help: the following other types implement trait `FromSql<A, DB>`: <*const str as FromSql<diesel::sql_types::Text, DB>> <std::string::String as FromSql<ST, DB>> = note: required because of the requirements on the impl of `FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, Mysql>` for `std::string::String` = note: required because of the requirements on the impl of `Queryable<diesel::sql_types::Nullable<diesel::sql_types::Text>, Mysql>` for `std::string::String` = note: required because of the requirements on the impl of `LoadQuery<MysqlConnection, std::string::String>` for `diesel::query_builder::SelectStatement<table, query_builder::select_clause::SelectClause<columns::label>, query_builder::distinct_clause::NoDistinctClause, query_builder::where_clause::WhereClause<IsNotNull<columns::label>>, query_builder::order_clause::NoOrderClause, query_builder::limit_clause::LimitClause<diesel::expression::bound::Bound<BigInt, i64>>>` note: required by a bound in `first` --> /home/kmdreko/.cargo/registry/src/github.com-1ecc6299db9ec823/diesel-1.4.8/src/query_dsl/mod.rs:1343:22 | 1343 | Limit<Self>: LoadQuery<Conn, U>, | ^^^^^^^^^^^^^^^^^^ required by this bound in `first`
疑问
已知用Option<String>可以解决问题,但已经通过is_not_null()过滤确保值非空,能不能直接移除Nullable的包装器,必须手动unwrap结果吗?
解决方案
方法1:用NotNull移除Nullable包装
可以通过diesel::dsl::NotNull明确告知Diesel,该字段经过过滤后不会为空,直接映射到非Option类型:
use diesel::dsl::NotNull; let result: String = foo_dsl::Foo .select(NotNull::new(foo_dsl::label)) .filter(foo_dsl::label.is_not_null()) .first(&conn) .unwrap();
这个方法在查询层面完成类型转换,不需要后续手动unwrap。
方法2:手动unwrap(简单直接)
如果不想引入额外DSL类型,也可以先获取Option<String>再unwrap:
let result: String = foo_dsl::Foo .select(foo_dsl::label) .filter(foo_dsl::label.is_not_null()) .first(&conn) .unwrap() .unwrap();
逻辑直观,适合简单场景,但要注意:如果数据库存在并发修改导致字段变为NULL(概率极低),unwrap会触发panic,建议结合错误处理而非直接unwrap。
注意事项
NotNull需要Diesel 1.4及以上版本支持,旧版本需升级。
内容的提问来源于stack exchange,提问作者Ross Rogers
相关产品推荐
相关产品推荐

