refactor: fewer non-macro queries
Some checks failed
/ integration-test--firefox (push) Failing after 3m5s
Some checks failed
/ integration-test--firefox (push) Failing after 3m5s
This commit is contained in:
parent
69e23fd9bb
commit
84c41dda4d
5 changed files with 119 additions and 111 deletions
|
|
@ -1,10 +1,18 @@
|
|||
use chrono::{DateTime, NaiveDate, Utc};
|
||||
use sqlx::sqlite::SqliteRow;
|
||||
use sqlx::{FromRow, Row};
|
||||
use sqlx::sqlite::SqlitePool;
|
||||
use std::str::FromStr;
|
||||
|
||||
use super::Birthday;
|
||||
use crate::AppError;
|
||||
use crate::db::DbId;
|
||||
use crate::switchboard::MentionHostType;
|
||||
|
||||
struct RawContact {
|
||||
id: DbId,
|
||||
birthday: Option<String>,
|
||||
manually_freshened_at: Option<String>,
|
||||
lives_with: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Contact {
|
||||
|
|
@ -14,6 +22,31 @@ pub struct Contact {
|
|||
pub lives_with: String,
|
||||
}
|
||||
|
||||
impl Into<Contact> for RawContact {
|
||||
fn into(self) -> Contact {
|
||||
Contact {
|
||||
id: self.id,
|
||||
birthday: self
|
||||
.birthday
|
||||
.and_then(|s| Birthday::from_str(s.as_ref()).ok()),
|
||||
manually_freshened_at: self
|
||||
.manually_freshened_at
|
||||
.and_then(|str| DateTime::parse_from_str(str.as_ref(), "%+").ok())
|
||||
.map(|d| d.to_utc()),
|
||||
lives_with: self.lives_with,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct RawHydratedContact {
|
||||
id: DbId,
|
||||
birthday: Option<String>,
|
||||
manually_freshened_at: Option<String>,
|
||||
lives_with: String,
|
||||
last_mention_date: Option<String>,
|
||||
names: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct HydratedContact {
|
||||
pub contact: Contact,
|
||||
|
|
@ -21,6 +54,28 @@ pub struct HydratedContact {
|
|||
pub names: Vec<String>,
|
||||
}
|
||||
|
||||
impl Into<HydratedContact> for RawHydratedContact {
|
||||
fn into(self) -> HydratedContact {
|
||||
HydratedContact {
|
||||
contact: Into::<Contact>::into(RawContact {
|
||||
id: self.id,
|
||||
birthday: self.birthday,
|
||||
manually_freshened_at: self.manually_freshened_at,
|
||||
lives_with: self.lives_with,
|
||||
}),
|
||||
names: self
|
||||
.names
|
||||
.unwrap_or(String::new())
|
||||
.split('\x1c')
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<String>>(),
|
||||
last_mention_date: self
|
||||
.last_mention_date
|
||||
.and_then(|str| NaiveDate::from_str(str.as_ref()).ok()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for HydratedContact {
|
||||
type Target = Contact;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
|
|
@ -36,54 +91,60 @@ impl HydratedContact {
|
|||
"(unnamed)".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRow<'_, SqliteRow> for Contact {
|
||||
fn from_row(row: &SqliteRow) -> sqlx::Result<Self> {
|
||||
let id: DbId = row.try_get("id")?;
|
||||
pub async fn load(id: DbId, pool: &SqlitePool) -> Result<Self, AppError> {
|
||||
// copy-paste the query from 'all', then add "where c.id = $2" to the last line
|
||||
let raw = sqlx::query_as!(
|
||||
RawHydratedContact,
|
||||
r#"select id, birthday, lives_with, manually_freshened_at as "manually_freshened_at: String", (
|
||||
select string_agg(name,'\x1c' order by sort)
|
||||
from names where contact_id = c.id
|
||||
) as names, (
|
||||
select jes.date from journal_entries jes
|
||||
join mentions ms on ms.entity_id = jes.id
|
||||
where ms.entity_type = $1
|
||||
and ms.url = '/contact/'||c.id
|
||||
or ms.url in (
|
||||
select '/group/'||slug from groups where
|
||||
contact_id = c.id
|
||||
)
|
||||
order by jes.date desc limit 1
|
||||
) as last_mention_date from contacts c
|
||||
where c.id = $2"#,
|
||||
MentionHostType::JournalEntry as DbId,
|
||||
id
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
|
||||
let birthday = Birthday::from_row(row).ok();
|
||||
Ok(Into::<HydratedContact>::into(raw))
|
||||
}
|
||||
|
||||
let manually_freshened_at = row
|
||||
.try_get::<String, &str>("manually_freshened_at")
|
||||
.ok()
|
||||
.and_then(|str| {
|
||||
DateTime::parse_from_str(&str, "%+")
|
||||
.ok()
|
||||
.map(|d| d.to_utc())
|
||||
});
|
||||
pub async fn all(pool: &SqlitePool) -> Result<Vec<Self>, AppError> {
|
||||
let contacts = sqlx::query_as!(
|
||||
RawHydratedContact,
|
||||
r#"select id, birthday, lives_with, manually_freshened_at as "manually_freshened_at: String", (
|
||||
select string_agg(name,'\x1c' order by sort)
|
||||
from names where contact_id = c.id
|
||||
) as names, (
|
||||
select jes.date from journal_entries jes
|
||||
join mentions ms on ms.entity_id = jes.id
|
||||
where ms.entity_type = $1
|
||||
and ms.url = '/contact/'||c.id
|
||||
or ms.url in (
|
||||
select '/group/'||slug from groups where
|
||||
contact_id = c.id
|
||||
)
|
||||
order by jes.date desc limit 1
|
||||
) as last_mention_date from contacts c"#,
|
||||
MentionHostType::JournalEntry as DbId
|
||||
)
|
||||
.fetch_all(pool)
|
||||
.await?;
|
||||
|
||||
let lives_with: String = row.try_get("lives_with")?;
|
||||
|
||||
Ok(Self {
|
||||
id,
|
||||
birthday,
|
||||
manually_freshened_at,
|
||||
lives_with,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRow<'_, SqliteRow> for HydratedContact {
|
||||
fn from_row(row: &SqliteRow) -> sqlx::Result<Self> {
|
||||
let contact = Contact::from_row(row)?;
|
||||
|
||||
let names_str: String = row.try_get("names").unwrap_or("".to_string());
|
||||
let names = if names_str.is_empty() {
|
||||
vec![]
|
||||
} else {
|
||||
names_str.split('\x1c').map(|s| s.to_string()).collect()
|
||||
};
|
||||
|
||||
let last_mention_date = row
|
||||
.try_get::<String, &str>("last_mention_date")
|
||||
.ok()
|
||||
.and_then(|str| NaiveDate::from_str(&str).ok());
|
||||
|
||||
Ok(Self {
|
||||
contact,
|
||||
names,
|
||||
last_mention_date,
|
||||
})
|
||||
Ok(contacts
|
||||
.into_iter()
|
||||
.map(|raw| Into::<HydratedContact>::into(raw))
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue