brass/db/src/models/availability.rs

333 lines
10 KiB
Rust

use chrono::{NaiveDate, NaiveDateTime};
use sqlx::{PgPool, query, query_file};
use super::{Area, AvailabilityChangeset, Result, Role, User, UserFunction};
#[derive(Clone, Debug)]
pub struct Availability {
pub id: i32,
pub user_id: i32,
pub user: Option<User>,
pub start: NaiveDateTime,
pub end: NaiveDateTime,
pub comment: Option<String>,
}
impl Availability {
pub async fn create(
pool: &PgPool,
user_id: i32,
changeset: AvailabilityChangeset,
) -> Result<()> {
query_file!(
"sql/availability/create.sql",
user_id,
changeset.time.0.and_utc(),
changeset.time.1.and_utc(),
changeset.comment
)
.execute(pool)
.await?;
Ok(())
}
pub async fn read_all_by_date_and_area_including_user(
pool: &PgPool,
date: NaiveDate,
area_id: i32,
) -> Result<Vec<Availability>> {
let records = query_file!(
"sql/availability/read_all_by_date_and_area_including_user.sql",
date,
area_id
)
.fetch_all(pool)
.await?;
let availabilities = records
.iter()
.map(|r| Availability {
id: r.id,
user_id: r.userid,
user: Some(User {
id: r.userid,
name: r.name.clone(),
email: r.email.clone(),
password: r.password.clone(),
salt: r.salt.clone(),
role: r.role,
function: r.function.clone(),
area_id: r.areaid,
area: None,
locked: r.locked,
last_login: r.lastlogin,
receive_notifications: r.receivenotifications,
}),
start: r.starttimestamp.naive_utc(),
end: r.endtimestamp.naive_utc(),
comment: r.comment.clone(),
})
.collect();
Ok(availabilities)
}
/// loads availabilities for the area and the same day as the start date and which fully lie inside the daterange
pub async fn read_all_by_daterange_and_area_including_user_for_event_planning(
pool: &PgPool,
date_range: (NaiveDateTime, NaiveDateTime),
area_id: i32,
) -> Result<Vec<Availability>> {
let records = query_file!(
"sql/availability/read_all_by_daterange_and_area_including_user_for_event_planning.sql",
date_range.0.date(),
area_id,
date_range.0.and_utc(),
date_range.1.and_utc()
)
.fetch_all(pool)
.await?;
let availabilities = records
.iter()
.map(|r| Availability {
id: r.id,
user_id: r.userid,
user: Some(User {
id: r.userid,
name: r.name.clone(),
email: r.email.clone(),
password: r.password.clone(),
salt: r.salt.clone(),
role: r.role,
function: r.function.clone(),
area_id: r.areaid,
area: None,
locked: r.locked,
last_login: r.lastlogin,
receive_notifications: r.receivenotifications,
}),
start: r.starttimestamp.naive_utc(),
end: r.endtimestamp.naive_utc(),
comment: r.comment.clone(),
})
.collect();
Ok(availabilities)
}
pub async fn read_including_user(pool: &PgPool, id: i32) -> Result<Option<Availability>> {
let record = query_file!("sql/availability/read_including_user.sql", id)
.fetch_optional(pool)
.await?;
let availability = record.map(|r| Availability {
id: r.id,
user_id: r.userid,
user: Some(User {
id: r.userid,
name: r.name.clone(),
email: r.email.clone(),
password: r.password.clone(),
salt: r.salt.clone(),
role: r.role,
function: r.function.clone(),
area_id: r.areaid,
area: None,
locked: r.locked,
last_login: r.lastlogin,
receive_notifications: r.receivenotifications,
}),
start: r.starttimestamp.naive_utc(),
end: r.endtimestamp.naive_utc(),
comment: r.comment.clone(),
});
Ok(availability)
}
pub async fn read(pool: &PgPool, id: i32) -> Result<Option<Availability>> {
let record = query!("SELECT * FROM availability WHERE id = $1", id)
.fetch_optional(pool)
.await?;
let availability = record.map(|record| Availability {
id: record.id,
user_id: record.userid,
user: None,
start: record.starttimestamp.naive_utc(),
end: record.endtimestamp.naive_utc(),
comment: record.comment.clone(),
});
Ok(availability)
}
pub async fn read_all_by_daterange_and_area_including_user_for_export(
pool: &PgPool,
date_range: (NaiveDate, NaiveDate),
area_id: i32,
) -> Result<Vec<Availability>> {
let records = query_file!(
"sql/availability/read_all_by_daterange_and_area_including_user_for_export.sql",
area_id,
date_range.0,
date_range.1
)
.fetch_all(pool)
.await?;
let availabilities = records
.iter()
.map(|r| Availability {
id: r.id,
user_id: r.userid,
user: Some(User {
id: r.userid,
name: r.name.clone(),
email: r.email.clone(),
password: r.password.clone(),
salt: r.salt.clone(),
role: r.role,
function: r.function.clone(),
area_id: r.areaid,
area: Some(Area {
id: r.areaid,
name: r.areaname.clone(),
}),
locked: r.locked,
last_login: r.lastlogin,
receive_notifications: r.receivenotifications,
}),
start: r.starttimestamp.naive_utc(),
end: r.endtimestamp.naive_utc(),
comment: r.comment.clone(),
})
.collect();
Ok(availabilities)
}
pub async fn read_all_by_user_and_date(
pool: &PgPool,
user_id: i32,
date: &NaiveDate,
) -> Result<Vec<Availability>> {
let records = query_file!(
"sql/availability/read_all_by_user_and_date.sql",
user_id,
date
)
.fetch_all(pool)
.await?;
let availabilities = records
.iter()
.map(|r| Availability {
id: r.id,
user_id: r.userid,
user: None,
start: r.starttimestamp.naive_utc(),
end: r.endtimestamp.naive_utc(),
comment: r.comment.clone(),
})
.collect();
Ok(availabilities)
}
pub async fn read_all_by_user_and_daterange(
pool: &PgPool,
user_id: i32,
date_range: (&NaiveDate, &NaiveDate),
) -> Result<Vec<Availability>> {
let records = query_file!(
"sql/availability/read_all_by_user_and_daterange.sql",
user_id,
date_range.0,
date_range.1
)
.fetch_all(pool)
.await?;
let availabilities = records
.iter()
.map(|r| Availability {
id: r.id,
user_id: r.userid,
user: None,
start: r.starttimestamp.naive_utc(),
end: r.endtimestamp.naive_utc(),
comment: r.comment.clone(),
})
.collect();
Ok(availabilities)
}
pub async fn find_adjacent_by_time_for_user(
pool: &PgPool,
start: &NaiveDateTime,
end: &NaiveDateTime,
user: i32,
availability_to_ignore: Option<i32>,
) -> Result<Option<Availability>> {
let records = query!(
r##"
SELECT
availability.id,
availability.userId,
availability.startTimestamp,
availability.endTimestamp,
availability.comment
FROM availability
WHERE availability.userId = $1
AND (availability.endtimestamp = $2
OR availability.starttimestamp = $3)
AND (availability.id <> $4 OR $4 IS NULL);
"##,
user,
start.and_utc(),
end.and_utc(),
availability_to_ignore
)
.fetch_all(pool) // possible to find up to two availabilities (upper and lower), for now we only pick one and extend it
.await?;
let adjacent_avaialability = records.first().and_then(|r| {
Some(Availability {
id: r.id,
user_id: r.userid,
user: None,
start: r.starttimestamp.naive_utc(),
end: r.endtimestamp.naive_utc(),
comment: r.comment.clone(),
})
});
Ok(adjacent_avaialability)
}
pub async fn update(pool: &PgPool, id: i32, changeset: AvailabilityChangeset) -> Result<()> {
query!(
"UPDATE availability SET startTimestamp = $1, endTimestamp = $2, comment = $3 WHERE id = $4",
changeset.time.0.and_utc(),
changeset.time.1.and_utc(),
changeset.comment,
id
)
.execute(pool)
.await?;
Ok(())
}
pub async fn delete(pool: &PgPool, id: i32) -> Result<()> {
query!("DELETE FROM availability WHERE id = $1", id)
.execute(pool)
.await?;
Ok(())
}
}