Is there a sea-orm equivalent to findOrCreate? How else would I do this?
from nerdblood@programming.dev to rust@programming.dev on 24 Sep 2023 23:21
https://programming.dev/post/3453451

in sequelize (javascript) it’s pretty straightforward to either find a record, or create it if it doesn’t exist. I don’t see anything similar with sea-orm. There’s a ‘save’ method that seems to insert or update, but I need to know details about the record ahead of time :/

Any ideas?

sequelize.org/docs/v6/…/model-querying-finders/

#rust

threaded - newest

nerdblood@programming.dev on 25 Sep 2023 00:27 collapse

I managed to get this working, but there has to be a better way. How else could I write this?

  pub async fn insert_or_return_user(
        db: &DbConn,
        partial_user: Auth0UserPart,
    ) -> Result {
        let user = users::ActiveModel {
            email: Set(partial_user.email.to_owned()),
            email_verified: Set(partial_user.email_verified.to_owned()),
            auth0_sub: Set(partial_user.sub.to_owned()),
            ..Default::default()
        };

        let result = user.clone().insert(db).await;

        match result {
            Ok(u) => {
                println!("{u:#?}");
                Ok(u.try_into_model().unwrap() as UsersModel)
            }
            Err(error) => {
                let user = Users::find()
                    .filter(users::Column::Auth0Sub.eq(&partial_user.sub))
                    .one(db)
                    .await?;

                Ok(user.unwrap() as UsersModel)
            }
        }
    }
snaggen@programming.dev on 25 Sep 2023 05:50 next collapse

I have never used sea-orm, but I wonder if .on_conflict could be used to simplify the code above?

BitSound@lemmy.world on 25 Sep 2023 13:50 next collapse

This is likely what OP will have to do. It actually looks like ANSI SQL now has merge, but you can scroll down a bit and see how each DB handles it slightly differently if you don’t use merge.

nerdblood@programming.dev on 27 Sep 2023 02:09 collapse

I think I had that in a few attempts, I can’t remember why I removed it. Thanks for pointing this out.

Lmaydev@programming.dev on 25 Sep 2023 11:59 collapse

I would likely do it in reverse. Try and find the object and if it doesn’t exist create it.

snaggen@programming.dev on 25 Sep 2023 13:20 collapse

That will always be prune to race conditions, where you check if someting exists (then some other thread creates it) and then you try to create it. You should always try to create first, then if it fails due to it already existing, fetch it. That is a good general rule for anything from hashmaps to databases.

BitSound@lemmy.world on 25 Sep 2023 13:54 next collapse

That’s true, but also trying to create first has a race condition too. The above code will panic at the unwrap if the record is deleted after the failed insert, and before the select

snaggen@programming.dev on 25 Sep 2023 17:03 collapse

So, a loop it is…

nerdblood@programming.dev on 27 Sep 2023 02:11 collapse

I’m new to multithreaded programming. How would some other thread create it? Like what’s the real-world scenario?

snaggen@programming.dev on 27 Sep 2023 05:03 collapse

That is all dependent on the program, but the simplest scenario is by an API with two requests at the same time. But it may also be like if you scan for new files, and use inotify, then you may also have a scanning loop as a fallback. Then the scan and inotify may trigger at almost the same time, so if that then results in a db create or insert you can get in to this problem. So, there are multiple ways to get in to trouble, and life always find new ways 😀

nerdblood@programming.dev on 28 Sep 2023 02:28 collapse

Indeed it does haha, thanks