- Self::create_conn(conn, domain).await
- }
- pub async fn create_from_actor_id(pool: &DbPool, actor_id: &Url) -> Result<Self, Error> {
- let domain = actor_id.host_str().expect("actor id missing a domain");
- Self::create(pool, domain).await
- }
- pub async fn create_conn(conn: &mut AsyncPgConnection, domain: &str) -> Result<Self, Error> {
- let form = InstanceForm::builder()
- .domain(domain.to_string())
- .updated(Some(naive_now()))
- .build();
- Self::create_from_form_conn(conn, &form).await
+
+ // First try to read the instance row and return directly if found
+ let instance = instance::table
+ .filter(domain.eq(&domain_))
+ .first::<Self>(conn)
+ .await;
+ match instance {
+ Ok(i) => Ok(i),
+ Err(diesel::NotFound) => {
+ // Instance not in database yet, insert it
+ let form = InstanceForm::builder()
+ .domain(domain_)
+ .updated(Some(naive_now()))
+ .build();
+ insert_into(instance::table)
+ .values(&form)
+ // Necessary because this method may be called concurrently for the same domain. This
+ // could be handled with a transaction, but nested transactions arent allowed
+ .on_conflict(instance::domain)
+ .do_update()
+ .set(&form)
+ .get_result::<Self>(conn)
+ .await
+ }
+ e => e,
+ }