]> Untitled Git - lemmy.git/blobdiff - crates/db_schema/src/impls/instance.rs
Make functions work with both connection and pool (#3420)
[lemmy.git] / crates / db_schema / src / impls / instance.rs
index c2afa6ae1de4882fd1a006454f4e4522adc88e2e..068e317fc8e37600d20dc6afd549b72596e53a95 100644 (file)
@@ -2,58 +2,80 @@ use crate::{
   newtypes::InstanceId,
   schema::{federation_allowlist, federation_blocklist, instance},
   source::instance::{Instance, InstanceForm},
-  utils::naive_now,
+  utils::{get_conn, naive_now, DbPool},
 };
-use diesel::{dsl::*, result::Error, *};
-use lemmy_utils::utils::generate_domain_url;
-use url::Url;
+use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl};
+use diesel_async::RunQueryDsl;
 
 impl Instance {
-  fn create_from_form(conn: &mut PgConnection, form: &InstanceForm) -> Result<Self, Error> {
-    // Do upsert on domain name conflict
-    insert_into(instance::table)
-      .values(form)
-      .on_conflict(instance::domain)
-      .do_update()
-      .set(form)
-      .get_result::<Self>(conn)
-  }
-  pub fn create(conn: &mut PgConnection, domain: &str) -> Result<Self, Error> {
-    let form = InstanceForm {
-      domain: domain.to_string(),
-      updated: Some(naive_now()),
-    };
-    Self::create_from_form(conn, &form)
-  }
-  pub fn create_from_actor_id(conn: &mut PgConnection, actor_id: &Url) -> Result<Self, Error> {
-    let domain = &generate_domain_url(actor_id).expect("actor id missing a domain");
-    Self::create(conn, domain)
+  /// Attempt to read Instance column for the given domain. If it doesnt exist, insert a new one.
+  /// There is no need for update as the domain of an existing instance cant change.
+  pub async fn read_or_create(pool: &mut DbPool<'_>, domain_: String) -> Result<Self, Error> {
+    use crate::schema::instance::domain;
+    let conn = &mut get_conn(pool).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,
+    }
   }
-  pub fn delete(conn: &mut PgConnection, instance_id: InstanceId) -> Result<usize, Error> {
-    diesel::delete(instance::table.find(instance_id)).execute(conn)
+  pub async fn delete(pool: &mut DbPool<'_>, instance_id: InstanceId) -> Result<usize, Error> {
+    let conn = &mut get_conn(pool).await?;
+    diesel::delete(instance::table.find(instance_id))
+      .execute(conn)
+      .await
   }
-  pub fn delete_all(conn: &mut PgConnection) -> Result<usize, Error> {
-    diesel::delete(instance::table).execute(conn)
+  #[cfg(test)]
+  pub async fn delete_all(pool: &mut DbPool<'_>) -> Result<usize, Error> {
+    let conn = &mut get_conn(pool).await?;
+    diesel::delete(instance::table).execute(conn).await
   }
-  pub fn allowlist(conn: &mut PgConnection) -> Result<Vec<String>, Error> {
+  pub async fn allowlist(pool: &mut DbPool<'_>) -> Result<Vec<Self>, Error> {
+    let conn = &mut get_conn(pool).await?;
     instance::table
       .inner_join(federation_allowlist::table)
-      .select(instance::domain)
-      .load::<String>(conn)
+      .select(instance::all_columns)
+      .get_results(conn)
+      .await
   }
 
-  pub fn blocklist(conn: &mut PgConnection) -> Result<Vec<String>, Error> {
+  pub async fn blocklist(pool: &mut DbPool<'_>) -> Result<Vec<Self>, Error> {
+    let conn = &mut get_conn(pool).await?;
     instance::table
       .inner_join(federation_blocklist::table)
-      .select(instance::domain)
-      .load::<String>(conn)
+      .select(instance::all_columns)
+      .get_results(conn)
+      .await
   }
 
-  pub fn linked(conn: &mut PgConnection) -> Result<Vec<String>, Error> {
+  pub async fn linked(pool: &mut DbPool<'_>) -> Result<Vec<Self>, Error> {
+    let conn = &mut get_conn(pool).await?;
     instance::table
       .left_join(federation_blocklist::table)
       .filter(federation_blocklist::id.is_null())
-      .select(instance::domain)
-      .load::<String>(conn)
+      .select(instance::all_columns)
+      .get_results(conn)
+      .await
   }
 }