Dataloader für BenutzerGruppen und BenutzerRollen hinzugefügt
This commit is contained in:
parent
f410791d4b
commit
bfce29c8ee
|
@ -317,6 +317,7 @@ dependencies = [
|
||||||
"dotenv",
|
"dotenv",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"envy",
|
"envy",
|
||||||
|
"itertools 0.13.0",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
|
@ -1138,6 +1139,15 @@ dependencies = [
|
||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.11"
|
version = "1.0.11"
|
||||||
|
@ -1986,7 +1996,7 @@ version = "0.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c"
|
checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itertools",
|
"itertools 0.12.1",
|
||||||
"nom",
|
"nom",
|
||||||
"unicode_categories",
|
"unicode_categories",
|
||||||
]
|
]
|
||||||
|
@ -2647,6 +2657,18 @@ checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
"serde",
|
"serde",
|
||||||
|
"uuid-macro-internal",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid-macro-internal"
|
||||||
|
version = "1.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6b91f57fe13a38d0ce9e28a03463d8d3c2468ed03d75375110ec71d93b449a08"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -31,10 +31,12 @@ serde = "1.0.215"
|
||||||
tokio = { version = "1.39.1", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.39.1", features = ["macros", "rt-multi-thread"] }
|
||||||
|
|
||||||
# UUID
|
# UUID
|
||||||
uuid = { version = "1.11.0", features = ["serde", "v4"] }
|
uuid = { version = "1.11.0", features = ["serde", "v4", "macro-diagnostics"] }
|
||||||
ulid = { version = "1.1.3", features = ["uuid"] }
|
ulid = { version = "1.1.3", features = ["uuid"] }
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
tracing = "0.1.41"
|
tracing = "0.1.41"
|
||||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "chrono"] }
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "chrono"] }
|
||||||
tracing-appender = "0.2.3"
|
tracing-appender = "0.2.3"
|
||||||
|
|
||||||
|
itertools = "0.13.0"
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
-- Add down migration script here
|
||||||
|
DROP TYPE gruppen_herkunft;;
|
|
@ -0,0 +1,5 @@
|
||||||
|
CREATE TYPE gruppen_herkunft AS ENUM (
|
||||||
|
'direkt',
|
||||||
|
'indirekt',
|
||||||
|
'beides'
|
||||||
|
);
|
|
@ -0,0 +1,51 @@
|
||||||
|
use async_graphql::dataloader::*;
|
||||||
|
use async_graphql::*;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::models::gruppe::Gruppe;
|
||||||
|
use crate::scalar::Id;
|
||||||
|
|
||||||
|
pub struct BenutzerGruppenLoader {
|
||||||
|
pub pool: sqlx::PgPool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Loader<Id> for BenutzerGruppenLoader {
|
||||||
|
type Value = Vec<Gruppe>;
|
||||||
|
type Error = Arc<sqlx::Error>;
|
||||||
|
|
||||||
|
async fn load(&self, keys: &[Id]) -> Result<HashMap<Id, Self::Value>, Self::Error> {
|
||||||
|
let rows = sqlx::query!(
|
||||||
|
r#"
|
||||||
|
SELECT
|
||||||
|
bg.benutzer_id,
|
||||||
|
g.id,
|
||||||
|
g.gruppenname,
|
||||||
|
g.erstellt_am,
|
||||||
|
g.geaendert_am
|
||||||
|
FROM gruppen AS g
|
||||||
|
LEFT JOIN benutzer_gruppen AS bg ON g.id = bg.gruppe_id
|
||||||
|
WHERE bg.benutzer_id = ANY($1);
|
||||||
|
"#,
|
||||||
|
keys
|
||||||
|
)
|
||||||
|
.fetch_all(&self.pool)
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.map(|row| {
|
||||||
|
(
|
||||||
|
row.benutzer_id,
|
||||||
|
Gruppe {
|
||||||
|
id: row.id,
|
||||||
|
gruppenname: row.gruppenname,
|
||||||
|
erstellt_am: row.erstellt_am,
|
||||||
|
geaendert_am: row.geaendert_am,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.into_group_map();
|
||||||
|
|
||||||
|
Ok(rows)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
use async_graphql::dataloader::*;
|
||||||
|
use async_graphql::*;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::models::gruppe_ansicht::{GruppeAnsicht, Herkunft};
|
||||||
|
use crate::scalar::Id;
|
||||||
|
|
||||||
|
pub struct BenutzerGruppenKumulativLoader {
|
||||||
|
pub pool: sqlx::PgPool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Loader<Id> for BenutzerGruppenKumulativLoader {
|
||||||
|
type Value = Vec<GruppeAnsicht>;
|
||||||
|
type Error = Arc<sqlx::Error>;
|
||||||
|
|
||||||
|
async fn load(&self, keys: &[Id]) -> Result<HashMap<Id, Self::Value>, Self::Error> {
|
||||||
|
let rows = sqlx::query!(
|
||||||
|
r#"
|
||||||
|
SELECT DISTINCT
|
||||||
|
COALESCE(bg.benutzer_id, br.benutzer_id) AS benutzer_id,
|
||||||
|
g.id AS gruppe_id,
|
||||||
|
g.gruppenname,
|
||||||
|
g.erstellt_am,
|
||||||
|
g.geaendert_am,
|
||||||
|
CASE WHEN br.benutzer_id IS NOT null THEN r.rollenname END AS rollenname,
|
||||||
|
CASE
|
||||||
|
WHEN bg.benutzer_id IS NOT NULL AND br.benutzer_id IS NOT NULL THEN 'beides'::gruppen_herkunft
|
||||||
|
WHEN bg.benutzer_id IS NOT NULL THEN 'direkt'::gruppen_herkunft
|
||||||
|
WHEN br.benutzer_id IS NOT NULL THEN 'indirekt'::gruppen_herkunft
|
||||||
|
END AS "herkunft: Herkunft"
|
||||||
|
FROM gruppen AS g
|
||||||
|
LEFT JOIN
|
||||||
|
benutzer_gruppen AS bg
|
||||||
|
ON
|
||||||
|
g.id = bg.gruppe_id
|
||||||
|
AND bg.benutzer_id = ANY($1)
|
||||||
|
LEFT JOIN rollen_gruppen AS rg ON g.id = rg.gruppe_id
|
||||||
|
LEFT JOIN
|
||||||
|
benutzer_rollen AS br
|
||||||
|
ON
|
||||||
|
rg.rolle_id = br.rolle_id
|
||||||
|
AND br.benutzer_id = ANY($1)
|
||||||
|
LEFT JOIN rollen AS r ON rg.rolle_id = r.id
|
||||||
|
WHERE
|
||||||
|
bg.benutzer_id = ANY($1)
|
||||||
|
OR br.benutzer_id = ANY($1);
|
||||||
|
"#,
|
||||||
|
keys
|
||||||
|
)
|
||||||
|
.fetch_all(&self.pool)
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.map(|row| {
|
||||||
|
(
|
||||||
|
row.benutzer_id.unwrap(),
|
||||||
|
GruppeAnsicht {
|
||||||
|
id: row.gruppe_id,
|
||||||
|
gruppenname: row.gruppenname,
|
||||||
|
rollenname: row.rollenname,
|
||||||
|
herkunft: row.herkunft.unwrap(),
|
||||||
|
erstellt_am: row.erstellt_am,
|
||||||
|
geaendert_am: row.geaendert_am,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.into_group_map();
|
||||||
|
|
||||||
|
Ok(rows)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
use async_graphql::dataloader::*;
|
||||||
|
use async_graphql::*;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::models::rolle::Rolle;
|
||||||
|
use crate::scalar::Id;
|
||||||
|
|
||||||
|
pub struct BenutzerRollenLoader {
|
||||||
|
pub pool: sqlx::PgPool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Loader<Id> for BenutzerRollenLoader {
|
||||||
|
type Value = Vec<Rolle>;
|
||||||
|
type Error = Arc<sqlx::Error>;
|
||||||
|
|
||||||
|
async fn load(&self, keys: &[Id]) -> Result<HashMap<Id, Self::Value>, Self::Error> {
|
||||||
|
let rows = sqlx::query!(
|
||||||
|
r#"
|
||||||
|
SELECT
|
||||||
|
br.benutzer_id,
|
||||||
|
r.id,
|
||||||
|
r.rollenname,
|
||||||
|
r.erstellt_am,
|
||||||
|
r.geaendert_am
|
||||||
|
FROM rollen AS r
|
||||||
|
LEFT JOIN benutzer_rollen AS br ON r.id = br.rolle_id
|
||||||
|
WHERE br.benutzer_id = ANY($1);
|
||||||
|
"#,
|
||||||
|
keys
|
||||||
|
)
|
||||||
|
.fetch_all(&self.pool)
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.map(|row| {
|
||||||
|
(
|
||||||
|
row.benutzer_id,
|
||||||
|
Rolle {
|
||||||
|
id: row.id,
|
||||||
|
rollenname: row.rollenname,
|
||||||
|
erstellt_am: row.erstellt_am,
|
||||||
|
geaendert_am: row.geaendert_am,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.into_group_map();
|
||||||
|
|
||||||
|
Ok(rows)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
mod benutzer_gruppen;
|
||||||
|
mod benutzer_gruppen_kumulativ;
|
||||||
|
mod benutzer_rollen;
|
||||||
|
mod rollen_gruppen;
|
||||||
|
|
||||||
|
pub use benutzer_gruppen::BenutzerGruppenLoader;
|
||||||
|
pub use benutzer_gruppen_kumulativ::BenutzerGruppenKumulativLoader;
|
||||||
|
pub use benutzer_rollen::BenutzerRollenLoader;
|
||||||
|
pub use rollen_gruppen::RollenGruppenLoader;
|
||||||
|
|
||||||
|
use async_graphql::dataloader::DataLoader;
|
||||||
|
|
||||||
|
pub struct LoaderContext {
|
||||||
|
pub benutzer_gruppen: DataLoader<BenutzerGruppenLoader>,
|
||||||
|
pub benutzer_rollen: DataLoader<BenutzerRollenLoader>,
|
||||||
|
pub rollen_gruppen: DataLoader<RollenGruppenLoader>,
|
||||||
|
pub benutzer_gruppen_kumulativ: DataLoader<BenutzerGruppenKumulativLoader>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LoaderContext {
|
||||||
|
pub fn new(pool: sqlx::PgPool) -> Self {
|
||||||
|
Self {
|
||||||
|
benutzer_gruppen: DataLoader::new(
|
||||||
|
BenutzerGruppenLoader { pool: pool.clone() },
|
||||||
|
tokio::spawn,
|
||||||
|
),
|
||||||
|
benutzer_rollen: DataLoader::new(
|
||||||
|
BenutzerRollenLoader { pool: pool.clone() },
|
||||||
|
tokio::spawn,
|
||||||
|
),
|
||||||
|
rollen_gruppen: DataLoader::new(
|
||||||
|
RollenGruppenLoader { pool: pool.clone() },
|
||||||
|
tokio::spawn,
|
||||||
|
),
|
||||||
|
benutzer_gruppen_kumulativ: DataLoader::new(
|
||||||
|
BenutzerGruppenKumulativLoader { pool: pool.clone() },
|
||||||
|
tokio::spawn,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
use async_graphql::dataloader::*;
|
||||||
|
use async_graphql::*;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::models::gruppe::Gruppe;
|
||||||
|
use crate::scalar::Id;
|
||||||
|
|
||||||
|
pub struct RollenGruppenLoader {
|
||||||
|
pub pool: sqlx::PgPool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Loader<Id> for RollenGruppenLoader {
|
||||||
|
type Value = Vec<Gruppe>;
|
||||||
|
type Error = Arc<sqlx::Error>;
|
||||||
|
|
||||||
|
async fn load(&self, keys: &[Id]) -> Result<HashMap<Id, Self::Value>, Self::Error> {
|
||||||
|
let rows = sqlx::query!(
|
||||||
|
r#"
|
||||||
|
SELECT
|
||||||
|
rg.rolle_id,
|
||||||
|
g.id,
|
||||||
|
g.gruppenname,
|
||||||
|
g.erstellt_am,
|
||||||
|
g.geaendert_am
|
||||||
|
FROM gruppen AS g
|
||||||
|
LEFT JOIN rollen_gruppen AS rg ON g.id = rg.gruppe_id
|
||||||
|
WHERE rg.rolle_id = ANY($1);
|
||||||
|
"#,
|
||||||
|
keys
|
||||||
|
)
|
||||||
|
.fetch_all(&self.pool)
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.map(|row| {
|
||||||
|
(
|
||||||
|
row.rolle_id,
|
||||||
|
Gruppe {
|
||||||
|
id: row.id,
|
||||||
|
gruppenname: row.gruppenname,
|
||||||
|
erstellt_am: row.erstellt_am,
|
||||||
|
geaendert_am: row.geaendert_am,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.into_group_map();
|
||||||
|
|
||||||
|
Ok(rows)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,24 @@
|
||||||
SELECT
|
SELECT DISTINCT
|
||||||
g.id,
|
COALESCE(bg.benutzer_id, br.benutzer_id) AS benutzer_id,
|
||||||
|
g.id AS gruppe_id,
|
||||||
g.gruppenname,
|
g.gruppenname,
|
||||||
g.erstellt_am,
|
g.erstellt_am,
|
||||||
g.geaendert_am
|
g.geaendert_am,
|
||||||
|
CASE WHEN br.benutzer_id IS NOT null THEN r.rollenname END
|
||||||
|
AS rollenname
|
||||||
FROM gruppen AS g
|
FROM gruppen AS g
|
||||||
|
LEFT JOIN
|
||||||
|
benutzer_gruppen AS bg
|
||||||
|
ON
|
||||||
|
g.id = bg.gruppe_id
|
||||||
|
AND bg.benutzer_id = ANY($1)
|
||||||
LEFT JOIN rollen_gruppen AS rg ON g.id = rg.gruppe_id
|
LEFT JOIN rollen_gruppen AS rg ON g.id = rg.gruppe_id
|
||||||
WHERE rg.rolle_id = 1;
|
LEFT JOIN
|
||||||
|
benutzer_rollen AS br
|
||||||
|
ON
|
||||||
|
rg.rolle_id = br.rolle_id
|
||||||
|
AND br.benutzer_id = ANY($1)
|
||||||
|
LEFT JOIN rollen AS r ON rg.rolle_id = r.id
|
||||||
|
WHERE
|
||||||
|
bg.benutzer_id = ANY($1)
|
||||||
|
OR br.benutzer_id = ANY($1);
|
||||||
|
|
12
src/main.rs
12
src/main.rs
|
@ -9,6 +9,7 @@ use axum::{
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
use config::Config;
|
use config::Config;
|
||||||
|
use dataloader::LoaderContext;
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
use mutations::Mutation;
|
use mutations::Mutation;
|
||||||
use queries::Query;
|
use queries::Query;
|
||||||
|
@ -18,6 +19,7 @@ use tokio::net::TcpListener;
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
mod database;
|
mod database;
|
||||||
|
mod dataloader;
|
||||||
mod domain;
|
mod domain;
|
||||||
mod models;
|
mod models;
|
||||||
mod mutations;
|
mod mutations;
|
||||||
|
@ -38,12 +40,11 @@ async fn graphiql() -> impl IntoResponse {
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
// tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
// .with_max_level(tracing::Level::DEBUG)
|
.with_max_level(tracing::Level::TRACE)
|
||||||
// .init();
|
.init();
|
||||||
|
|
||||||
dotenv().ok();
|
dotenv().ok();
|
||||||
env_logger::init();
|
|
||||||
|
|
||||||
// Config::load();
|
// Config::load();
|
||||||
let config = Arc::new(Config::load()?);
|
let config = Arc::new(Config::load()?);
|
||||||
|
@ -51,7 +52,8 @@ async fn main() -> Result<()> {
|
||||||
let db_pool = PgPool::connect(&config.database.url).await?;
|
let db_pool = PgPool::connect(&config.database.url).await?;
|
||||||
|
|
||||||
let schema = Schema::build(Query::default(), Mutation::default(), EmptySubscription)
|
let schema = Schema::build(Query::default(), Mutation::default(), EmptySubscription)
|
||||||
.data(db_pool)
|
.data(LoaderContext::new(db_pool.clone()))
|
||||||
|
.data(db_pool.clone())
|
||||||
.finish();
|
.finish();
|
||||||
|
|
||||||
// println!("{}", &schema.sdl());
|
// println!("{}", &schema.sdl());
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use async_graphql::{ComplexObject, Context, FieldResult, SimpleObject};
|
use async_graphql::{ComplexObject, Context, FieldResult, SimpleObject};
|
||||||
use sqlx::PgPool;
|
|
||||||
|
|
||||||
use crate::{models::gruppe::Gruppe, scalar::Id};
|
use crate::{dataloader::LoaderContext, models::gruppe::Gruppe, models::rolle::Rolle, scalar::Id};
|
||||||
|
|
||||||
use super::rolle::Rolle;
|
use super::gruppe_ansicht::GruppeAnsicht;
|
||||||
|
|
||||||
#[derive(SimpleObject)]
|
#[derive(sqlx::FromRow, SimpleObject)]
|
||||||
#[graphql(complex)]
|
#[graphql(complex)]
|
||||||
pub struct Benutzer {
|
pub struct Benutzer {
|
||||||
/// Die UUID eines Benutzers
|
/// Die UUID eines Benutzers
|
||||||
|
@ -24,50 +23,22 @@ pub struct Benutzer {
|
||||||
#[ComplexObject]
|
#[ComplexObject]
|
||||||
impl Benutzer {
|
impl Benutzer {
|
||||||
/// Die Rollen des Benutzers
|
/// Die Rollen des Benutzers
|
||||||
pub async fn rollen<'ctx>(&self, ctx: &Context<'ctx>) -> FieldResult<Vec<Rolle>> {
|
pub async fn rollen<'ctx>(&self, ctx: &Context<'ctx>) -> FieldResult<Option<Vec<Rolle>>> {
|
||||||
let pool = ctx.data::<PgPool>()?;
|
let loader = ctx.data::<LoaderContext>()?;
|
||||||
|
Ok(loader.benutzer_rollen.load_one(self.id).await?)
|
||||||
let rows = sqlx::query_as!(
|
|
||||||
Rolle,
|
|
||||||
r#"
|
|
||||||
SELECT
|
|
||||||
r.id,
|
|
||||||
r.rollenname,
|
|
||||||
r.erstellt_am,
|
|
||||||
r.geaendert_am
|
|
||||||
FROM rollen AS r
|
|
||||||
LEFT JOIN benutzer_rollen AS br ON r.id = br.rolle_id
|
|
||||||
WHERE br.benutzer_id = $1;
|
|
||||||
"#,
|
|
||||||
&self.id
|
|
||||||
)
|
|
||||||
.fetch_all(pool)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(rows)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Die Gruppen des Benutzers
|
/// Die Gruppen des Benutzers
|
||||||
pub async fn gruppen<'ctx>(&self, ctx: &Context<'ctx>) -> FieldResult<Vec<Gruppe>> {
|
pub async fn gruppen<'ctx>(&self, ctx: &Context<'ctx>) -> FieldResult<Option<Vec<Gruppe>>> {
|
||||||
let pool = ctx.data::<PgPool>()?;
|
let loader = ctx.data::<LoaderContext>()?;
|
||||||
|
Ok(loader.benutzer_gruppen.load_one(self.id).await?)
|
||||||
let rows = sqlx::query_as!(
|
}
|
||||||
Gruppe,
|
/// Die Gruppen eines Benutzer kumulativ mit den Gruppen aus den Rollen
|
||||||
r#"
|
pub async fn gruppen_kumulativ<'ctx>(
|
||||||
SELECT
|
&self,
|
||||||
g.id,
|
ctx: &Context<'ctx>,
|
||||||
g.gruppenname,
|
) -> FieldResult<Option<Vec<GruppeAnsicht>>> {
|
||||||
g.erstellt_am,
|
let loader = ctx.data::<LoaderContext>()?;
|
||||||
g.geaendert_am
|
Ok(loader.benutzer_gruppen_kumulativ.load_one(self.id).await?)
|
||||||
FROM gruppen AS g
|
|
||||||
LEFT JOIN benutzer_gruppen AS bg ON g.id = bg.gruppe_id
|
|
||||||
WHERE bg.benutzer_id = $1;
|
|
||||||
"#,
|
|
||||||
&self.id
|
|
||||||
)
|
|
||||||
.fetch_all(pool)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(rows)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use async_graphql::{ComplexObject, SimpleObject};
|
||||||
|
|
||||||
use crate::scalar::{Id, Time};
|
use crate::scalar::{Id, Time};
|
||||||
|
|
||||||
#[derive(SimpleObject)]
|
#[derive(sqlx::FromRow, SimpleObject, Clone, Debug)]
|
||||||
#[graphql(complex)]
|
#[graphql(complex)]
|
||||||
pub struct Gruppe {
|
pub struct Gruppe {
|
||||||
/// Die UUIDl einer Gruppe
|
/// Die UUIDl einer Gruppe
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
use async_graphql::{ComplexObject, Enum, SimpleObject};
|
||||||
|
use sqlx::Type;
|
||||||
|
|
||||||
|
use crate::scalar::{Id, Time};
|
||||||
|
|
||||||
|
/// Aus welcher Quille die Gruppe stammt.
|
||||||
|
#[derive(Enum, Clone, Debug, Eq, Copy, PartialEq, Type)]
|
||||||
|
#[sqlx(type_name = "gruppen_herkunft", rename_all = "lowercase")]
|
||||||
|
pub enum Herkunft {
|
||||||
|
/// Die Gruppe wurde direkt dem Benutzer zugefügt
|
||||||
|
Direkt,
|
||||||
|
|
||||||
|
/// Die Gruppe wurde durch eine Rolle vergeben
|
||||||
|
Indirekt,
|
||||||
|
|
||||||
|
/// Die Gruppe ist sowohl direkt als auch indirekt zugefügt
|
||||||
|
Beides,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(sqlx::FromRow, SimpleObject, Clone, Debug)]
|
||||||
|
#[graphql(complex)]
|
||||||
|
pub struct GruppeAnsicht {
|
||||||
|
/// Die UUID einer Gruppe
|
||||||
|
pub id: Id,
|
||||||
|
|
||||||
|
/// Der Gruppenname
|
||||||
|
pub gruppenname: String,
|
||||||
|
|
||||||
|
/// Die Herkunft der Gruppe
|
||||||
|
pub herkunft: Herkunft,
|
||||||
|
|
||||||
|
/// Bei einer indirekten Zuweisung, wird der Rollenname angegeben
|
||||||
|
pub rollenname: Option<String>,
|
||||||
|
|
||||||
|
/// Wann die Gruppe erstellt wurde
|
||||||
|
pub erstellt_am: Time,
|
||||||
|
|
||||||
|
/// Wann die Gruppe geaendert wurde
|
||||||
|
pub geaendert_am: Time,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[ComplexObject]
|
||||||
|
impl GruppeAnsicht {}
|
|
@ -1,5 +1,6 @@
|
||||||
pub mod benutzer;
|
pub mod benutzer;
|
||||||
pub mod gruppe;
|
pub mod gruppe;
|
||||||
|
pub mod gruppe_ansicht;
|
||||||
pub mod hersteller;
|
pub mod hersteller;
|
||||||
pub mod modell;
|
pub mod modell;
|
||||||
pub mod rolle;
|
pub mod rolle;
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
use async_graphql::{ComplexObject, Context, FieldResult, SimpleObject};
|
use async_graphql::{ComplexObject, Context, FieldResult, SimpleObject};
|
||||||
use sqlx::PgPool;
|
|
||||||
|
|
||||||
use crate::scalar::{Id, Time};
|
use crate::{
|
||||||
|
dataloader::LoaderContext,
|
||||||
use super::gruppe::Gruppe;
|
models::gruppe::Gruppe,
|
||||||
|
scalar::{Id, Time},
|
||||||
|
};
|
||||||
|
|
||||||
/// Um die Administration zu erleichtern werden Gruppen in die Rollen hinzugefuegt
|
/// Um die Administration zu erleichtern werden Gruppen in die Rollen hinzugefuegt
|
||||||
#[derive(SimpleObject, Debug)]
|
#[derive(sqlx::FromRow, SimpleObject, Debug, Clone)]
|
||||||
#[graphql(complex)]
|
#[graphql(complex)]
|
||||||
pub struct Rolle {
|
pub struct Rolle {
|
||||||
/// Die uuid einer Rolle
|
/// Die uuid einer Rolle
|
||||||
|
@ -25,26 +26,29 @@ pub struct Rolle {
|
||||||
#[ComplexObject]
|
#[ComplexObject]
|
||||||
impl Rolle {
|
impl Rolle {
|
||||||
/// Die Gruppen in einer Rolle
|
/// Die Gruppen in einer Rolle
|
||||||
pub async fn gruppen<'ctx>(&self, ctx: &Context<'ctx>) -> FieldResult<Vec<Gruppe>> {
|
pub async fn gruppen<'ctx>(&self, ctx: &Context<'ctx>) -> FieldResult<Option<Vec<Gruppe>>> {
|
||||||
let pool = ctx.data::<PgPool>()?;
|
let loader = ctx.data::<LoaderContext>()?;
|
||||||
|
Ok(loader.rollen_gruppen.load_one(self.id).await?)
|
||||||
let rows = sqlx::query_as!(
|
//
|
||||||
Gruppe,
|
// let pool = ctx.data::<PgPool>()?;
|
||||||
r#"
|
//
|
||||||
SELECT
|
// let rows = sqlx::query_as!(
|
||||||
g.id,
|
// Gruppe,
|
||||||
g.gruppenname,
|
// r#"
|
||||||
g.erstellt_am,
|
// SELECT
|
||||||
g.geaendert_am
|
// g.id,
|
||||||
FROM gruppen AS g
|
// g.gruppenname,
|
||||||
LEFT JOIN rollen_gruppen AS rg ON g.id = rg.gruppe_id
|
// g.erstellt_am,
|
||||||
WHERE rg.rolle_id = $1;
|
// g.geaendert_am
|
||||||
"#,
|
// FROM gruppen AS g
|
||||||
&self.id
|
// LEFT JOIN rollen_gruppen AS rg ON g.id = rg.gruppe_id
|
||||||
)
|
// WHERE rg.rolle_id = $1;
|
||||||
.fetch_all(pool)
|
// "#,
|
||||||
.await?;
|
// &self.id
|
||||||
|
// )
|
||||||
Ok(rows)
|
// .fetch_all(pool)
|
||||||
|
// .await?;
|
||||||
|
//
|
||||||
|
// Ok(rows)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
pub mod hersteller;
|
pub mod hersteller;
|
||||||
pub mod modell;
|
pub mod modell;
|
||||||
pub mod typ;
|
pub mod typ;
|
||||||
|
|
||||||
use async_graphql::MergedObject;
|
use async_graphql::MergedObject;
|
||||||
|
|
||||||
#[derive(MergedObject, Default)]
|
#[derive(MergedObject, Default)]
|
||||||
|
|
Loading…
Reference in New Issue