create gruppen, rollen, etc...
This commit is contained in:
parent
bfce29c8ee
commit
623d28f77b
|
@ -1 +1,2 @@
|
|||
DROP TYPE gruppen_herkunft;
|
||||
DROP TABLE gruppen;
|
||||
|
|
|
@ -4,3 +4,9 @@ CREATE TABLE IF NOT EXISTS gruppen (
|
|||
erstellt_am TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
geaendert_am TIMESTAMP WITH TIME ZONE NOT NULL
|
||||
)
|
||||
|
||||
CREATE TYPE gruppen_herkunft AS ENUM (
|
||||
'direkt',
|
||||
'indirekt',
|
||||
'beides'
|
||||
);
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
-- Add down migration script here
|
||||
DROP TYPE gruppen_herkunft;;
|
|
@ -1,5 +0,0 @@
|
|||
CREATE TYPE gruppen_herkunft AS ENUM (
|
||||
'direkt',
|
||||
'indirekt',
|
||||
'beides'
|
||||
);
|
|
@ -8,7 +8,8 @@ use crate::config;
|
|||
pub type DB = Pool<Postgres>;
|
||||
pub trait Queryer<'c>: Executor<'c, Database = sqlx::Postgres> {}
|
||||
|
||||
impl<'c> Queryer<'c> for &Pool<Postgres> {}
|
||||
// impl<'c> Queryer<'c> for &Pool<Postgres> {}
|
||||
impl<'c> Queryer<'c> for &DB {}
|
||||
|
||||
pub async fn connect(database: &config::Database) -> Result<DB, Error> {
|
||||
PgPoolOptions::new()
|
||||
|
|
|
@ -4,7 +4,7 @@ use itertools::Itertools;
|
|||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::models::rolle::Rolle;
|
||||
use crate::domain::rolle::model::Rolle;
|
||||
use crate::scalar::Id;
|
||||
|
||||
pub struct BenutzerRollenLoader {
|
||||
|
|
|
@ -1,37 +1,27 @@
|
|||
mod benutzer_gruppen;
|
||||
mod benutzer_gruppen_kumulativ;
|
||||
mod benutzer_rollen;
|
||||
mod rollen_gruppen;
|
||||
|
||||
pub use benutzer_gruppen::BenutzerGruppenLoader;
|
||||
use crate::domain::{
|
||||
gruppe::dataloader::gruppen::GruppenLoader, rolle::dataloader::rollen::RollenLoader,
|
||||
};
|
||||
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 gruppen: DataLoader<GruppenLoader>,
|
||||
// pub benutzer_rollen: DataLoader<BenutzerRollenLoader>,
|
||||
pub rollen: DataLoader<RollenLoader>,
|
||||
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,
|
||||
),
|
||||
gruppen: DataLoader::new(GruppenLoader { pool: pool.clone() }, tokio::spawn),
|
||||
rollen: DataLoader::new(RollenLoader { pool: pool.clone() }, tokio::spawn),
|
||||
|
||||
benutzer_gruppen_kumulativ: DataLoader::new(
|
||||
BenutzerGruppenKumulativLoader { pool: pool.clone() },
|
||||
tokio::spawn,
|
||||
|
|
|
@ -4,7 +4,7 @@ use itertools::Itertools;
|
|||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::models::gruppe::Gruppe;
|
||||
use crate::domain::gruppe::model::Gruppe;
|
||||
use crate::scalar::Id;
|
||||
|
||||
pub struct RollenGruppenLoader {
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
pub mod benutzer;
|
||||
pub mod gruppe;
|
||||
pub mod rolle;
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
pub mod dataloader;
|
||||
pub mod entity;
|
||||
pub mod model;
|
||||
pub mod repository;
|
||||
pub mod service;
|
|
@ -0,0 +1,3 @@
|
|||
pub mod benutzer;
|
||||
|
||||
pub use benutzer::Benutzer;
|
|
@ -0,0 +1,8 @@
|
|||
use crate::scalar::Id;
|
||||
|
||||
pub struct Benutzer {
|
||||
pub id: Id,
|
||||
pub kennung: String,
|
||||
pub nachname: String,
|
||||
pub vorname: String,
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
pub mod benutzer;
|
||||
pub mod benutzer_create_input;
|
||||
|
||||
pub use benutzer::Benutzer;
|
||||
pub use benutzer_create_input::BenutzerCreateInput;
|
|
@ -1,8 +1,11 @@
|
|||
use async_graphql::{ComplexObject, Context, FieldResult, SimpleObject};
|
||||
|
||||
use crate::{dataloader::LoaderContext, models::gruppe::Gruppe, models::rolle::Rolle, scalar::Id};
|
||||
|
||||
use super::gruppe_ansicht::GruppeAnsicht;
|
||||
use crate::{
|
||||
dataloader::LoaderContext,
|
||||
domain::{gruppe::model::Gruppe, rolle::model::Rolle},
|
||||
models::gruppe_ansicht::GruppeAnsicht,
|
||||
scalar::Id,
|
||||
};
|
||||
|
||||
#[derive(sqlx::FromRow, SimpleObject)]
|
||||
#[graphql(complex)]
|
||||
|
@ -25,14 +28,15 @@ impl Benutzer {
|
|||
/// Die Rollen des Benutzers
|
||||
pub async fn rollen<'ctx>(&self, ctx: &Context<'ctx>) -> FieldResult<Option<Vec<Rolle>>> {
|
||||
let loader = ctx.data::<LoaderContext>()?;
|
||||
Ok(loader.benutzer_rollen.load_one(self.id).await?)
|
||||
Ok(loader.rollen.load_one(self.id).await?)
|
||||
}
|
||||
|
||||
/// Die Gruppen des Benutzers
|
||||
pub async fn gruppen<'ctx>(&self, ctx: &Context<'ctx>) -> FieldResult<Option<Vec<Gruppe>>> {
|
||||
let loader = ctx.data::<LoaderContext>()?;
|
||||
Ok(loader.benutzer_gruppen.load_one(self.id).await?)
|
||||
Ok(loader.gruppen.load_one(self.id).await?)
|
||||
}
|
||||
|
||||
/// Die Gruppen eines Benutzer kumulativ mit den Gruppen aus den Rollen
|
||||
pub async fn gruppen_kumulativ<'ctx>(
|
||||
&self,
|
|
@ -0,0 +1,12 @@
|
|||
use crate::scalar::Id;
|
||||
use async_graphql::InputObject;
|
||||
|
||||
#[derive(InputObject)]
|
||||
pub struct BenutzerCreateInput {
|
||||
// #[graphql(validator(min_length = 6, max_length = 8))]
|
||||
pub kennung: String,
|
||||
pub vorname: String,
|
||||
pub nachname: String,
|
||||
pub rollen: Option<Vec<Id>>,
|
||||
pub gruppen: Option<Vec<Id>>,
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
mod alle_benutzer;
|
||||
pub mod create_benutzer;
|
||||
pub mod find_gruppen;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Repository {}
|
||||
|
||||
impl Repository {
|
||||
pub fn new() -> Repository {
|
||||
Repository {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Repository {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
use anyhow::Error;
|
||||
|
||||
use super::Repository;
|
||||
use crate::database::Queryer;
|
||||
use crate::domain::benutzer::model;
|
||||
|
||||
impl Repository {
|
||||
pub async fn alle_benutzer<'c, C: Queryer<'c>>(
|
||||
&self,
|
||||
db: C,
|
||||
) -> Result<Vec<model::Benutzer>, Error> {
|
||||
const QUERY: &str = r#"
|
||||
SELECT *
|
||||
FROM benutzer
|
||||
"#;
|
||||
|
||||
let benutzer = sqlx::query_as::<_, model::Benutzer>(QUERY)
|
||||
.fetch_all(db)
|
||||
.await?;
|
||||
|
||||
Ok(benutzer)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
use anyhow::Error;
|
||||
|
||||
use super::Repository;
|
||||
use crate::database::Queryer;
|
||||
use crate::domain::benutzer::entity;
|
||||
use crate::domain::benutzer::model;
|
||||
use crate::scalar::Id;
|
||||
|
||||
impl Repository {
|
||||
pub async fn create_benutzer<'c, C: Queryer<'c>>(
|
||||
&self,
|
||||
db: C,
|
||||
benutzer: &entity::Benutzer,
|
||||
) -> Result<model::Benutzer, Error> {
|
||||
const QUERY: &str = r#"
|
||||
INSERT INTO benutzer (id, kennung, nachname, vorname)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING id, kennung, nachname, vorname;
|
||||
"#;
|
||||
|
||||
let benutzer = sqlx::query_as::<_, model::Benutzer>(QUERY)
|
||||
.bind::<Id>(benutzer.id)
|
||||
.bind(&benutzer.kennung)
|
||||
.bind(&benutzer.nachname)
|
||||
.bind(&benutzer.vorname)
|
||||
.fetch_one(db)
|
||||
.await?;
|
||||
|
||||
Ok(benutzer)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
use anyhow::Error;
|
||||
use async_graphql::Context;
|
||||
|
||||
use crate::domain::gruppe::model::Gruppe;
|
||||
|
||||
use super::Repository;
|
||||
|
||||
impl Repository {
|
||||
pub async fn find_gruppen<'a>(&self, ctx: &'a Context<'_>) -> Result<Vec<Gruppe>, Error> {
|
||||
// let rows = sqlx::query!(
|
||||
// r#"
|
||||
// SELECT
|
||||
// bg.benutzer_id,
|
||||
// g.id,
|
||||
// g.gruppenname,
|
||||
// g.erstellt_am
|
||||
// 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();
|
||||
// }
|
||||
todo!()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
mod alle_benutzer;
|
||||
pub mod create_benutzer;
|
||||
|
||||
use super::repository::Repository;
|
||||
use crate::database::DB;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Service {
|
||||
repo: Repository,
|
||||
pub db: DB,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn new(db: DB) -> Self {
|
||||
let repo = Repository::new();
|
||||
Self { repo, db }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
use async_graphql::FieldResult;
|
||||
|
||||
use crate::domain::benutzer::model::Benutzer;
|
||||
|
||||
use super::Service;
|
||||
|
||||
impl Service {
|
||||
pub async fn alle_benutzer(&self) -> FieldResult<Vec<Benutzer>> {
|
||||
Ok(self.repo.alle_benutzer(&self.db).await?)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
use async_graphql::FieldResult;
|
||||
use ulid::Ulid;
|
||||
|
||||
use crate::domain::benutzer::{
|
||||
entity,
|
||||
model::{Benutzer, BenutzerCreateInput},
|
||||
};
|
||||
|
||||
use super::Service;
|
||||
|
||||
impl Service {
|
||||
pub async fn create_benutzer(&self, input: BenutzerCreateInput) -> FieldResult<Benutzer> {
|
||||
let benutzer_entity = entity::Benutzer {
|
||||
id: Ulid::new().into(),
|
||||
kennung: input.kennung,
|
||||
nachname: input.nachname,
|
||||
vorname: input.vorname,
|
||||
};
|
||||
|
||||
Ok(self
|
||||
.repo
|
||||
.create_benutzer(&self.db, &benutzer_entity)
|
||||
.await?)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
pub mod dataloader;
|
||||
pub mod entity;
|
||||
pub mod model;
|
||||
pub mod repository;
|
||||
pub mod service;
|
|
@ -0,0 +1 @@
|
|||
pub mod gruppen;
|
|
@ -0,0 +1,24 @@
|
|||
use async_graphql::dataloader::*;
|
||||
use async_graphql::*;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::domain::gruppe::model::Gruppe;
|
||||
use crate::domain::gruppe::service::Service;
|
||||
use crate::scalar::Id;
|
||||
|
||||
pub struct GruppenLoader {
|
||||
pub pool: sqlx::PgPool,
|
||||
}
|
||||
|
||||
impl Loader<Id> for GruppenLoader {
|
||||
type Value = Vec<Gruppe>;
|
||||
type Error = Arc<sqlx::Error>;
|
||||
|
||||
async fn load(&self, keys: &[Id]) -> Result<HashMap<Id, Self::Value>, Self::Error> {
|
||||
let rows = Service::new(self.pool.clone())
|
||||
.gruppe_dataloader(keys)
|
||||
.await?;
|
||||
Ok(rows)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
pub mod gruppe;
|
||||
pub use gruppe::Gruppe;
|
|
@ -0,0 +1,8 @@
|
|||
use crate::scalar::{Id, Time};
|
||||
|
||||
pub struct Gruppe {
|
||||
pub id: Id,
|
||||
pub gruppenname: String,
|
||||
pub erstellt_am: Option<Time>,
|
||||
pub geaendert_am: Option<Time>,
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
pub mod gruppe;
|
||||
pub mod gruppe_erstelle_input;
|
||||
pub mod gruppe_update_input;
|
||||
|
||||
pub use gruppe::Gruppe;
|
||||
pub use gruppe_erstelle_input::GruppeErstelleInput;
|
||||
pub use gruppe_update_input::GruppeUpdateInput;
|
|
@ -0,0 +1,7 @@
|
|||
use async_graphql::InputObject;
|
||||
|
||||
#[derive(InputObject)]
|
||||
pub struct GruppeErstelleInput {
|
||||
/// Der Name einer Gruppe
|
||||
pub gruppenname: String,
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
use async_graphql::InputObject;
|
||||
|
||||
#[derive(InputObject)]
|
||||
pub struct GruppeUpdateInput {
|
||||
/// Der Name einer Gruppe
|
||||
pub gruppenname: String,
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
mod gruppe_alle;
|
||||
mod gruppe_dataloader;
|
||||
mod gruppe_erstellen;
|
||||
mod gruppe_update;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Repository {}
|
||||
|
||||
impl Repository {
|
||||
pub fn new() -> Repository {
|
||||
Repository {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Repository {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
use anyhow::Error;
|
||||
|
||||
use super::Repository;
|
||||
use crate::{database::Queryer, domain::gruppe::model};
|
||||
|
||||
impl Repository {
|
||||
pub async fn gruppe_alle<'c, C: Queryer<'c>>(
|
||||
&self,
|
||||
db: C,
|
||||
) -> Result<Vec<model::Gruppe>, Error> {
|
||||
const QUERY: &str = r#"
|
||||
SELECT * FROM gruppen
|
||||
"#;
|
||||
|
||||
let gruppen = sqlx::query_as::<_, model::Gruppe>(QUERY)
|
||||
.fetch_all(db)
|
||||
.await?;
|
||||
|
||||
Ok(gruppen)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
use super::Repository;
|
||||
use crate::database::Queryer;
|
||||
use crate::domain::gruppe::model::Gruppe;
|
||||
use crate::scalar::Id;
|
||||
|
||||
impl Repository {
|
||||
pub async fn gruppe_dataloader<'c, C: Queryer<'c>>(
|
||||
&self,
|
||||
db: C,
|
||||
keys: &[Id],
|
||||
) -> Result<HashMap<Id, Vec<Gruppe>>, Arc<sqlx::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(db)
|
||||
.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,29 @@
|
|||
use anyhow::Error;
|
||||
|
||||
use super::Repository;
|
||||
use crate::database::Queryer;
|
||||
use crate::domain::gruppe::{entity, model};
|
||||
|
||||
impl Repository {
|
||||
pub async fn gruppe_erstellen<'c, C: Queryer<'c>>(
|
||||
&self,
|
||||
db: C,
|
||||
gruppe: &entity::Gruppe,
|
||||
) -> Result<model::Gruppe, Error> {
|
||||
const QUERY: &str = r#"
|
||||
INSERT INTO gruppen (id, erstellt_am, geaendert_am, gruppenname) VALUES (
|
||||
$1, $2, $3, $4
|
||||
) RETURNING id, erstellt_am, geaendert_am, gruppenname;
|
||||
"#;
|
||||
|
||||
let gruppe = sqlx::query_as::<_, model::Gruppe>(QUERY)
|
||||
.bind(gruppe.id)
|
||||
.bind(gruppe.erstellt_am)
|
||||
.bind(gruppe.geaendert_am)
|
||||
.bind(&gruppe.gruppenname)
|
||||
.fetch_one(db)
|
||||
.await?;
|
||||
|
||||
Ok(gruppe)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
use anyhow::Error;
|
||||
|
||||
use super::Repository;
|
||||
use crate::database::Queryer;
|
||||
use crate::domain::gruppe::{entity, model};
|
||||
|
||||
impl Repository {
|
||||
pub async fn gruppe_update<'c, C: Queryer<'c>>(
|
||||
&self,
|
||||
db: C,
|
||||
gruppe: &entity::Gruppe,
|
||||
) -> Result<model::Gruppe, Error> {
|
||||
const QUERY: &str = r#"
|
||||
UPDATE gruppen
|
||||
SET geaendert_am = $2, ruppenname = $3 WHERE gruppeid = $1
|
||||
RETURNING id, geaendert_am, gruppenname, gruppenname;
|
||||
"#;
|
||||
|
||||
let gruppe = sqlx::query_as::<_, model::Gruppe>(QUERY)
|
||||
.bind(gruppe.id)
|
||||
.bind(gruppe.geaendert_am)
|
||||
.bind(&gruppe.gruppenname)
|
||||
.fetch_one(db)
|
||||
.await?;
|
||||
|
||||
Ok(gruppe)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
mod gruppe_alle;
|
||||
mod gruppe_dataloader;
|
||||
mod gruppe_erstellen;
|
||||
mod gruppe_update;
|
||||
|
||||
use super::repository::Repository;
|
||||
use crate::database::DB;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Service {
|
||||
repo: Repository,
|
||||
pub db: DB,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn new(db: DB) -> Self {
|
||||
let repo = Repository::new();
|
||||
Self { repo, db }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
use anyhow::Error;
|
||||
|
||||
use crate::domain::gruppe::model;
|
||||
|
||||
use super::Service;
|
||||
|
||||
impl Service {
|
||||
pub async fn gruppe_alle(&self) -> Result<Vec<model::Gruppe>, Error> {
|
||||
let gruppe = self.repo.gruppe_alle(&self.db).await?;
|
||||
Ok(gruppe)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use crate::{domain::gruppe::model::Gruppe, scalar::Id};
|
||||
|
||||
use super::Service;
|
||||
|
||||
impl Service {
|
||||
pub async fn gruppe_dataloader(
|
||||
&self,
|
||||
keys: &[Id],
|
||||
) -> Result<HashMap<Id, Vec<Gruppe>>, Arc<sqlx::Error>> {
|
||||
let grupen_dataloader = self.repo.gruppe_dataloader(&self.db, keys).await?;
|
||||
Ok(grupen_dataloader)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
use anyhow::Error;
|
||||
use chrono::Utc;
|
||||
use ulid::Ulid;
|
||||
|
||||
use super::Service;
|
||||
use crate::domain::gruppe::{
|
||||
entity,
|
||||
model::{self, GruppeErstelleInput},
|
||||
};
|
||||
|
||||
impl Service {
|
||||
pub async fn gruppe_erstellen(
|
||||
&self,
|
||||
input: GruppeErstelleInput,
|
||||
) -> Result<model::Gruppe, Error> {
|
||||
let gruppe_input = entity::Gruppe {
|
||||
id: Ulid::new().into(),
|
||||
gruppenname: input.gruppenname,
|
||||
erstellt_am: Some(Utc::now()),
|
||||
geaendert_am: Some(Utc::now()),
|
||||
};
|
||||
|
||||
let gruppe = self.repo.gruppe_erstellen(&self.db, &gruppe_input).await?;
|
||||
Ok(gruppe)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
use anyhow::Error;
|
||||
use chrono::Utc;
|
||||
use ulid::Ulid;
|
||||
|
||||
use super::Service;
|
||||
use crate::domain::gruppe::{
|
||||
entity,
|
||||
model::{self, GruppeUpdateInput},
|
||||
};
|
||||
|
||||
impl Service {
|
||||
pub async fn gruppe_update(&self, input: GruppeUpdateInput) -> Result<model::Gruppe, Error> {
|
||||
let gruppe_input = entity::Gruppe {
|
||||
id: Ulid::new().into(),
|
||||
gruppenname: input.gruppenname,
|
||||
erstellt_am: None,
|
||||
geaendert_am: Some(Utc::now()),
|
||||
};
|
||||
|
||||
let gruppe = self.repo.gruppe_erstellen(&self.db, &gruppe_input).await?;
|
||||
Ok(gruppe)
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
pub mod dataloader;
|
||||
pub mod entity;
|
||||
pub mod model;
|
||||
pub mod mutation;
|
||||
pub mod repository;
|
||||
pub mod service;
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
pub mod rollen;
|
|
@ -4,29 +4,29 @@ use itertools::Itertools;
|
|||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::models::gruppe::Gruppe;
|
||||
use crate::domain::rolle::model::Rolle;
|
||||
use crate::scalar::Id;
|
||||
|
||||
pub struct BenutzerGruppenLoader {
|
||||
pub struct RollenLoader {
|
||||
pub pool: sqlx::PgPool,
|
||||
}
|
||||
|
||||
impl Loader<Id> for BenutzerGruppenLoader {
|
||||
type Value = Vec<Gruppe>;
|
||||
impl Loader<Id> for RollenLoader {
|
||||
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
|
||||
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);
|
||||
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
|
||||
)
|
||||
|
@ -36,9 +36,9 @@ impl Loader<Id> for BenutzerGruppenLoader {
|
|||
.map(|row| {
|
||||
(
|
||||
row.benutzer_id,
|
||||
Gruppe {
|
||||
Rolle {
|
||||
id: row.id,
|
||||
gruppenname: row.gruppenname,
|
||||
rollenname: row.rollenname,
|
||||
erstellt_am: row.erstellt_am,
|
||||
geaendert_am: row.geaendert_am,
|
||||
},
|
|
@ -1,9 +1,8 @@
|
|||
use crate::scalar::{Id, Time};
|
||||
|
||||
#[derive(sqlx::FromRow)]
|
||||
pub struct Rolle {
|
||||
pub id: Id,
|
||||
pub created_at: Time,
|
||||
pub updated_at: Time,
|
||||
pub rollenname: String,
|
||||
pub erstellt_am: Time,
|
||||
pub geaendert_am: Time,
|
||||
}
|
||||
|
|
|
@ -2,6 +2,5 @@ mod rolle;
|
|||
mod rolle_create_input;
|
||||
mod rolle_update_input;
|
||||
|
||||
pub use rolle::Gruppe;
|
||||
pub use rolle::Rolle;
|
||||
pub use rolle_create_input::RolleCreateInput;
|
||||
|
|
|
@ -1,36 +1,33 @@
|
|||
use async_graphql::SimpleObject;
|
||||
use async_graphql::{ComplexObject, Context, FieldResult, SimpleObject};
|
||||
|
||||
use crate::scalar::{Id, Time};
|
||||
use crate::{
|
||||
dataloader::LoaderContext,
|
||||
domain::gruppe::model::Gruppe,
|
||||
scalar::{Id, Time},
|
||||
};
|
||||
|
||||
#[derive(Debug, SimpleObject, sqlx::FromRow)]
|
||||
/// Um die Administration zu erleichtern werden Gruppen in die Rollen hinzugefuegt
|
||||
#[derive(sqlx::FromRow, SimpleObject, Debug, Clone)]
|
||||
#[graphql(complex)]
|
||||
pub struct Rolle {
|
||||
/// Die ID einer Rolle
|
||||
/// Die uuid einer Rolle
|
||||
pub id: Id,
|
||||
|
||||
/// Zeit wann die Rolle erstellt wurde
|
||||
pub created_at: Time,
|
||||
|
||||
/// Zeit wann die Rolle geändert wurde
|
||||
pub updated_at: Time,
|
||||
|
||||
/// Der Name einer Rolle
|
||||
/// Der Rollenname
|
||||
pub rollenname: String,
|
||||
|
||||
pub gruppen: Vec<Gruppe>,
|
||||
/// Wann die Rolle erstellt wurde
|
||||
pub erstellt_am: Time,
|
||||
|
||||
/// Wann die Rolle geaendert wurde
|
||||
pub geaendert_am: Time,
|
||||
}
|
||||
|
||||
/// TODO: Migration in ein separates Modul
|
||||
#[derive(Debug, SimpleObject, sqlx::Type)]
|
||||
pub struct Gruppe {
|
||||
/// Die ID einer Gruppe
|
||||
pub id: Id,
|
||||
|
||||
/// Zeit wann die Gruppe erstellt wurde
|
||||
pub created_at: Time,
|
||||
|
||||
///Zeit wann die Gruppe geändert wurde
|
||||
pub updated_at: Time,
|
||||
|
||||
/// Der Name einer Gruppe
|
||||
pub gruppenname: String,
|
||||
#[ComplexObject]
|
||||
impl Rolle {
|
||||
/// Die Gruppen in einer Rolle
|
||||
pub async fn gruppen<'ctx>(&self, ctx: &Context<'ctx>) -> FieldResult<Option<Vec<Gruppe>>> {
|
||||
let loader = ctx.data::<LoaderContext>()?;
|
||||
Ok(loader.gruppen.load_one(self.id).await?)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ mod create_rolle;
|
|||
mod delete_rolle;
|
||||
mod find_all_rolle;
|
||||
mod find_rolle_by_id;
|
||||
mod rollen_dataloader;
|
||||
mod update_rolle;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
@ -16,8 +16,8 @@ impl Repository {
|
|||
|
||||
match sqlx::query_scalar::<_, Id>(QUERY)
|
||||
.bind(rolle.id)
|
||||
.bind(rolle.created_at)
|
||||
.bind(rolle.updated_at)
|
||||
.bind(rolle.erstellt_am)
|
||||
.bind(rolle.geaendert_am)
|
||||
.bind(&rolle.rollenname)
|
||||
.fetch_one(db)
|
||||
.await
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
use super::Repository;
|
||||
use crate::database::Queryer;
|
||||
use crate::domain::rolle::model::Rolle;
|
||||
use crate::scalar::Id;
|
||||
|
||||
impl Repository {
|
||||
pub async fn rollen_dataloader<'c, C: Queryer<'c>>(
|
||||
&self,
|
||||
db: C,
|
||||
keys: &[Id],
|
||||
) -> Result<HashMap<Id, Vec<Rolle>>, Arc<sqlx::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(db)
|
||||
.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)
|
||||
}
|
||||
}
|
|
@ -16,8 +16,8 @@ impl Service {
|
|||
let rolle_input = entity::Rolle {
|
||||
id: Ulid::new().into(),
|
||||
rollenname: input.rollenname,
|
||||
created_at: Utc::now(),
|
||||
updated_at: Utc::now(),
|
||||
erstellt_am: Utc::now(),
|
||||
geaendert_am: Utc::now(),
|
||||
};
|
||||
|
||||
let created_id = self.repo.create_rolle(&self.db, &rolle_input).await?;
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
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
|
||||
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);
|
|
@ -1,7 +1,4 @@
|
|||
pub mod benutzer;
|
||||
pub mod gruppe;
|
||||
pub mod gruppe_ansicht;
|
||||
pub mod hersteller;
|
||||
pub mod modell;
|
||||
pub mod rolle;
|
||||
pub mod typ;
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
use async_graphql::{ComplexObject, Context, FieldResult, SimpleObject};
|
||||
|
||||
use crate::{
|
||||
dataloader::LoaderContext,
|
||||
models::gruppe::Gruppe,
|
||||
scalar::{Id, Time},
|
||||
};
|
||||
|
||||
/// Um die Administration zu erleichtern werden Gruppen in die Rollen hinzugefuegt
|
||||
#[derive(sqlx::FromRow, SimpleObject, Debug, Clone)]
|
||||
#[graphql(complex)]
|
||||
pub struct Rolle {
|
||||
/// Die uuid einer Rolle
|
||||
pub id: Id,
|
||||
|
||||
/// Der Rollenname
|
||||
pub rollenname: String,
|
||||
|
||||
/// Wann die Rolle erstellt wurde
|
||||
pub erstellt_am: Time,
|
||||
|
||||
/// Wann die Rolle geaendert wurde
|
||||
pub geaendert_am: Time,
|
||||
}
|
||||
|
||||
#[ComplexObject]
|
||||
impl Rolle {
|
||||
/// Die Gruppen in einer Rolle
|
||||
pub async fn gruppen<'ctx>(&self, ctx: &Context<'ctx>) -> FieldResult<Option<Vec<Gruppe>>> {
|
||||
let loader = ctx.data::<LoaderContext>()?;
|
||||
Ok(loader.rollen_gruppen.load_one(self.id).await?)
|
||||
//
|
||||
// let pool = ctx.data::<PgPool>()?;
|
||||
//
|
||||
// let rows = sqlx::query_as!(
|
||||
// Gruppe,
|
||||
// r#"
|
||||
// SELECT
|
||||
// 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 = $1;
|
||||
// "#,
|
||||
// &self.id
|
||||
// )
|
||||
// .fetch_all(pool)
|
||||
// .await?;
|
||||
//
|
||||
// Ok(rows)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
use crate::domain::benutzer::{model::Benutzer, model::BenutzerCreateInput, service::Service};
|
||||
use async_graphql::{Context, FieldResult};
|
||||
use sqlx::postgres::PgPool;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BenutzerMutation;
|
||||
|
||||
#[async_graphql::Object]
|
||||
impl BenutzerMutation {
|
||||
async fn create_benutzer(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
input: BenutzerCreateInput,
|
||||
) -> FieldResult<Benutzer> {
|
||||
let pool = ctx.data::<PgPool>()?;
|
||||
|
||||
let row = Service::new(pool.clone()).create_benutzer(input).await?;
|
||||
|
||||
Ok(row)
|
||||
}
|
||||
|
||||
// async fn update_hersteller(
|
||||
// &self,
|
||||
// ctx: &Context<'_>,
|
||||
// input: HerstellerUpdateInput,
|
||||
// ) -> FieldResult<Hersteller> {
|
||||
// let pool = ctx.data::<PgPool>()?;
|
||||
// let row = Hersteller::update(pool, &input).await?;
|
||||
// Ok(row)
|
||||
// }
|
||||
|
||||
// async fn delete_hersteller(&self, ctx: &Context<'_>, id: Id) -> FieldResult<bool> {
|
||||
// let pool = ctx.data::<PgPool>()?;
|
||||
// Ok(Hersteller::delete(pool, &id).await?)
|
||||
// }
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
use crate::domain::gruppe::{
|
||||
model::{Gruppe, GruppeErstelleInput},
|
||||
service::Service,
|
||||
};
|
||||
use async_graphql::{Context, FieldResult};
|
||||
use sqlx::postgres::PgPool;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct GruppeMutation;
|
||||
|
||||
#[async_graphql::Object]
|
||||
impl GruppeMutation {
|
||||
async fn gruppe_ersellen(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
input: GruppeErstelleInput,
|
||||
) -> FieldResult<Gruppe> {
|
||||
let pool = ctx.data::<PgPool>()?;
|
||||
|
||||
let gruppe = Service::new(pool.clone()).gruppe_erstellen(input).await?;
|
||||
Ok(gruppe)
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
pub mod benutzer;
|
||||
pub mod gruppe;
|
||||
pub mod hersteller;
|
||||
pub mod modell;
|
||||
pub mod typ;
|
||||
|
@ -9,4 +11,6 @@ pub struct Mutation(
|
|||
typ::TypMutation,
|
||||
hersteller::HerstellerMutation,
|
||||
modell::ModellMutation,
|
||||
benutzer::BenutzerMutation,
|
||||
gruppe::GruppeMutation,
|
||||
);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use async_graphql::{Context, FieldResult, Object};
|
||||
use sqlx::postgres::PgPool;
|
||||
|
||||
use crate::models::benutzer::Benutzer;
|
||||
use crate::domain::benutzer::{model::Benutzer, service::Service};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BenutzerQuery {}
|
||||
|
@ -17,9 +17,7 @@ impl BenutzerQuery {
|
|||
async fn benutzer_alle<'a>(&self, ctx: &'a Context<'_>) -> FieldResult<Vec<Benutzer>> {
|
||||
let pool = ctx.data::<PgPool>()?;
|
||||
|
||||
let benutzer = sqlx::query_as!(Benutzer, "SELECT * FROM benutzer")
|
||||
.fetch_all(pool)
|
||||
.await?;
|
||||
let benutzer = Service::new(pool.clone()).alle_benutzer().await?;
|
||||
|
||||
Ok(benutzer)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
use async_graphql::{Context, FieldResult, Object};
|
||||
use sqlx::postgres::PgPool;
|
||||
|
||||
use crate::domain::gruppe::{model::Gruppe, service::Service};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct GruppeQuery {}
|
||||
|
||||
#[Object(extends)]
|
||||
impl GruppeQuery {
|
||||
async fn gruppe<'a>(&self, ctx: &'a Context<'_>, id: uuid::Uuid) -> FieldResult<Gruppe> {
|
||||
todo!();
|
||||
// let pool = ctx.data::<PgPool>()?;
|
||||
//
|
||||
// Ok(row)
|
||||
}
|
||||
|
||||
async fn gruppen<'a>(&self, ctx: &'a Context<'_>) -> FieldResult<Vec<Gruppe>> {
|
||||
let pool = ctx.data::<PgPool>()?;
|
||||
let rows = Service::new(pool.clone()).gruppe_alle().await?;
|
||||
Ok(rows)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
pub mod benutzer;
|
||||
pub mod gruppe;
|
||||
pub mod hersteller;
|
||||
pub mod modell;
|
||||
pub mod rolle;
|
||||
|
@ -13,4 +14,5 @@ pub struct Query(
|
|||
hersteller::HerstellerQuery,
|
||||
benutzer::BenutzerQuery,
|
||||
rolle::RolleQuery,
|
||||
gruppe::GruppeQuery,
|
||||
);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use async_graphql::{Context, FieldResult, Object};
|
||||
use sqlx::postgres::PgPool;
|
||||
|
||||
use crate::models::rolle::Rolle;
|
||||
use crate::domain::rolle::model::Rolle;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RolleQuery {}
|
||||
|
|
Loading…
Reference in New Issue