210 lines
6.3 KiB
Rust
210 lines
6.3 KiB
Rust
use diesel::prelude::*;
|
|
use juniper::{graphql_object, EmptySubscription, FieldResult, IntoFieldError, RootNode};
|
|
use std::fs;
|
|
use uuidv7::Uuid;
|
|
|
|
use crate::{db, prune_many, prune_single, CONFIG};
|
|
|
|
pub mod context;
|
|
pub mod error;
|
|
pub mod loaders;
|
|
pub mod models;
|
|
pub mod scalars;
|
|
|
|
pub use context::Context;
|
|
pub use error::{Error, QueryResultIntoFieldResult};
|
|
|
|
use loaders::TryOptionLoad;
|
|
|
|
pub struct Query;
|
|
|
|
#[graphql_object(context = Context)]
|
|
impl Query {
|
|
fn ping() -> &'static str {
|
|
"pong"
|
|
}
|
|
|
|
async fn directories(context: &Context) -> FieldResult<Vec<models::directory::Directory>> {
|
|
let db_conn = &mut context.get_db_conn()?;
|
|
let ids: Vec<Uuid> = db::schema::directories::table
|
|
.select(db::schema::directories::id)
|
|
.filter(db::schema::directories::active)
|
|
.load(db_conn)
|
|
.into_field_result()?;
|
|
|
|
context
|
|
.loaders
|
|
.directory
|
|
.try_load_many(ids)
|
|
.await
|
|
.map_or_else(
|
|
|_| Err(Error::Internal.into_field_error()),
|
|
|x| Ok(x.into_values().collect()),
|
|
)
|
|
}
|
|
|
|
async fn directory(
|
|
context: &Context,
|
|
id: scalars::Uuid,
|
|
) -> FieldResult<Option<models::directory::Directory>> {
|
|
context
|
|
.loaders
|
|
.directory
|
|
.try_option_load(*id)
|
|
.await
|
|
.map_err(|_| Error::Internal.into_field_error())
|
|
}
|
|
}
|
|
|
|
pub struct Mutation;
|
|
|
|
#[graphql_object(context = Context)]
|
|
impl Mutation {
|
|
async fn create_directory(context: &Context) -> FieldResult<models::directory::Directory> {
|
|
let db_conn = &mut context.get_db_conn()?;
|
|
let id = diesel::insert_into(db::schema::directories::table)
|
|
.values(db::models::NewDirectory { active: true })
|
|
.returning(db::schema::directories::id)
|
|
.get_result::<Uuid>(db_conn)
|
|
.into_field_result()?;
|
|
|
|
fs::create_dir(format!("{}/{}", CONFIG.data_dir, id))
|
|
.map_err(|_| Error::Internal.into_field_error())?;
|
|
|
|
context
|
|
.loaders
|
|
.directory
|
|
.try_load(id)
|
|
.await
|
|
.map_err(|_| Error::Internal.into_field_error())
|
|
}
|
|
|
|
async fn create_directories(
|
|
context: &Context,
|
|
count: i32,
|
|
) -> FieldResult<Vec<models::directory::Directory>> {
|
|
match count {
|
|
_ if count < 0 => return Err(Error::CountNegative.into_field_error()),
|
|
0 => return Ok(vec![]),
|
|
_ => {}
|
|
}
|
|
|
|
let db_conn = &mut context.get_db_conn()?;
|
|
|
|
let input = vec![db::models::NewDirectory { active: true }];
|
|
let ids = diesel::insert_into(db::schema::directories::table)
|
|
.values(
|
|
input
|
|
.iter()
|
|
.cycle()
|
|
.take(count as usize)
|
|
.collect::<Vec<_>>(),
|
|
)
|
|
.returning(db::schema::directories::id)
|
|
.load::<Uuid>(db_conn)
|
|
.into_field_result()?;
|
|
|
|
for id in ids.iter() {
|
|
fs::create_dir(format!("{}/{}", CONFIG.data_dir, id))
|
|
.map_err(|_| Error::Internal.into_field_error())?;
|
|
}
|
|
|
|
context
|
|
.loaders
|
|
.directory
|
|
.try_load_many(ids)
|
|
.await
|
|
.map_or_else(
|
|
|_| Err(Error::Internal.into_field_error()),
|
|
|x| Ok(x.into_values().collect()),
|
|
)
|
|
}
|
|
|
|
async fn delete_directory(
|
|
context: &Context,
|
|
id: scalars::Uuid,
|
|
immediate: Option<bool>,
|
|
) -> FieldResult<bool> {
|
|
let db_conn = &mut context.get_db_conn()?;
|
|
|
|
if diesel::select(diesel::dsl::not(diesel::dsl::exists(
|
|
db::schema::directories::table.filter(db::schema::directories::id.eq(*id)),
|
|
)))
|
|
.get_result::<bool>(db_conn)
|
|
.into_field_result()?
|
|
{
|
|
return Err(Error::DoesNotExist.into_field_error());
|
|
}
|
|
|
|
if immediate.unwrap_or(false) {
|
|
prune_single(&id.to_string()).map_err(|_| Error::Internal.into_field_error())?;
|
|
diesel::delete(
|
|
db::schema::directories::table.filter(db::schema::directories::id.eq(*id)),
|
|
)
|
|
.execute(db_conn)
|
|
.into_field_result()?;
|
|
} else {
|
|
diesel::update(
|
|
db::schema::directories::table.filter(db::schema::directories::id.eq(*id)),
|
|
)
|
|
.set(db::schema::directories::active.eq(false))
|
|
.execute(db_conn)
|
|
.into_field_result()?;
|
|
}
|
|
|
|
Ok(true)
|
|
}
|
|
|
|
async fn delete_directories(
|
|
context: &Context,
|
|
ids: Vec<scalars::Uuid>,
|
|
immediate: Option<bool>,
|
|
) -> FieldResult<bool> {
|
|
let db_conn = &mut context.get_db_conn()?;
|
|
|
|
let ids: Vec<Uuid> = ids.into_iter().map(|id| *id).collect();
|
|
|
|
let count: i64 = db::schema::directories::table
|
|
.filter(db::schema::directories::id.eq_any(&ids))
|
|
.count()
|
|
.get_result::<i64>(db_conn)
|
|
.into_field_result()?;
|
|
dbg!(&count);
|
|
|
|
if count == ids.len() as i64 {
|
|
if immediate.unwrap_or(false) {
|
|
prune_many(&ids.iter().map(|id| id.to_string()).collect::<Vec<_>>())?;
|
|
diesel::delete(
|
|
db::schema::directories::table.filter(db::schema::directories::id.eq_any(ids)),
|
|
)
|
|
.execute(db_conn)
|
|
.into_field_result()?;
|
|
} else {
|
|
diesel::update(
|
|
db::schema::directories::table.filter(db::schema::directories::id.eq_any(ids)),
|
|
)
|
|
.set(db::schema::directories::active.eq(false))
|
|
.execute(db_conn)
|
|
.into_field_result()?;
|
|
}
|
|
} else {
|
|
return Err(Error::DoesNotExist.into_field_error());
|
|
}
|
|
|
|
Ok(true)
|
|
}
|
|
|
|
async fn prune(context: &Context) -> FieldResult<bool> {
|
|
let db_conn = &mut context.get_db_conn()?;
|
|
crate::prune(db_conn).map_err(|_| Error::Internal.into_field_error())?;
|
|
|
|
Ok(true)
|
|
}
|
|
}
|
|
|
|
pub type Schema = RootNode<'static, Query, Mutation, EmptySubscription<Context>>;
|
|
|
|
pub fn schema() -> Schema {
|
|
Schema::new(Query, Mutation, EmptySubscription::new())
|
|
}
|