sea-orm
sea-orm copied to clipboard
Convert from ActiveModel to Model
Summary
Right now it is impossible to convert from ActiveModel -> Model or from ActiveValue<T> -> T ?
Motivation
When using insert_many(..) the return type is useless. ( I assume this is to support MySQL which does not allow returning clause)
So I need to get the models back by making another round-trip to the database (not the end of the world) or converting the ActiveModel's.
However, from my Vec<ActiveModel>, I cannot find a way to go to Vec<Model> or even Vec<Uuid>.
This makes it very hard to get the result of a multi-insert.
Just my 2cts but, assuming you know that 1. Value is set and 2. Value is of type Uuid, wouldn't it be possible to use Value.as_ref_uuid() for the values?
For example, (going to Vec<Uuid> would be possible by using collect instead of for_each):
use sea_orm::ActiveValue;
use uuid::Uuid;
pub fn test() {
let test_uuids = vec![
ActiveValue::set(Uuid::new_v4()),
ActiveValue::set(Uuid::new_v4()),
ActiveValue::set(Uuid::new_v4()),
ActiveValue::set(Uuid::new_v4()),
ActiveValue::set(Uuid::new_v4()),
];
test_uuids
.iter() // Iter<ActiveValue<…>>
.cloned() // impl Iter<Item = ActiveValue<…>>
// unpack uuids
.map(|active_value| {
active_value // ActiveValue<…>
.into_value() // Option<Value>
.unwrap() // Value
.as_ref_uuid() // Option<&Uuid>
.unwrap() // &Uuid
.clone() // Uuid
}) // impl Iter<Item = Uuid>
.for_each(|uuid| {
// test if uuids are usable
println!("Uuid: {uuid}");
});
}
I think there are two problems:
-
convert from ActiveModel into Model, which is sadly lacking for now. but I think it's a "good first issue", because our derive macros already generated the code for Model into ActiveModel, so it should be a mirror of that. The catch is, if any of the ActiveModel fields are
NotSet, the conversion should fail (returnErr). -
convert from ActiveValue<T> to T, which, thanks @Chaostheorie for the explanation. The trick is you should always know what type to expect in Rust.
What is the difference between ActiveModel and Model?
Hey @kirawi, Model is an readonly struct that was retrieved from db. While ActiveModel is a stateful Model that was used for insert / update a row in the db.
https://www.sea-ql.org/SeaORM/docs/basic-crud/insert#model--activemodel
Hi @billy1624 , I'm a new comer and would like to work on this 'good first issue'. I'd appreciate it if you could give me some instructions.
Hey @greenhandatsjtu, thanks for reaching out!
I think we can starts small, and take on the first task...
- convert from ActiveModel into Model, which is sadly lacking for now. but I think it's a "good first issue", because our derive macros already generated the code for Model into ActiveModel, so it should be a mirror of that. The catch is, if any of the ActiveModel fields are
NotSet, the conversion should fail (returnErr).
We could introduce a new trait, TryIntoModel, for this conversion behaviour. Similar to the conversion from Model to ActiveModel.
pub trait TryIntoModel<M>
where
A: ModelTrait,
{
fn try_into_model(self) -> Result<M, DbErr>;
}
Then, we implement it inside derive macros of active model. Again, similar to what we did for converting Model into ActiveModel but in reverse.
impl std::convert::TryFrom<ActiveModel> for <Entity as EntityTrait>::Model { ... }
impl sea_orm::TryIntoModel<<Entity as EntityTrait>::Model> for ActiveModel { ... }
@billy1624 thanks for your advice, now I know where to start. I will try to work on the first task, but I'm not sure I can make it, sorry if I bother you again when I meet problems that I can't solve. Or should I make a draft PR if I've made some progess, so you can point out where's wrong or what to do next in that PR, not in this issue anymore? Thanks again for your patient guidance!
Hey @greenhandatsjtu, it's perfectly okay to ping me :D Please open a draft PR if you got any progress, all community members are encourage to conduct code review.