refactor Ulid und Dataloader
This commit is contained in:
@@ -1 +1,3 @@
|
|||||||
DROP DOMAIN ULID CASCADE;
|
DROP DOMAIN ulid CASCADE;
|
||||||
|
DROP EXTENSION IF EXISTS ltree;
|
||||||
|
DROP EXTENSION IF EXISTS "uuid-ossp";
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
CREATE DOMAIN ULID AS CHAR(26);
|
CREATE DOMAIN ulid AS CHAR(26);
|
||||||
|
CREATE EXTENSION IF NOT EXISTS ltree;
|
||||||
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
CREATE TABLE IF NOT EXISTS hersteller (
|
CREATE TABLE IF NOT EXISTS hersteller (
|
||||||
hersteller_id UUID PRIMARY KEY,
|
hersteller_id UUID PRIMARY KEY,
|
||||||
id CHAR(26) UNIQUE NOT NULL,
|
id ULID UNIQUE NOT NULL,
|
||||||
herstellername VARCHAR NOT NULL,
|
herstellername VARCHAR NOT NULL,
|
||||||
erstellt_am TIMESTAMP WITH TIME ZONE NOT NULL,
|
erstellt_am TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||||
geaendert_am TIMESTAMP WITH TIME ZONE NOT NULL
|
geaendert_am TIMESTAMP WITH TIME ZONE NOT NULL
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
CREATE TABLE IF NOT EXISTS gruppen (
|
CREATE TABLE IF NOT EXISTS gruppen (
|
||||||
id UUID PRIMARY KEY,
|
gruppe_id UUID PRIMARY KEY,
|
||||||
|
id ULID UNIQUE NOT NULL,
|
||||||
gruppenname VARCHAR NOT NULL,
|
gruppenname VARCHAR NOT NULL,
|
||||||
erstellt_am TIMESTAMP WITH TIME ZONE NOT NULL,
|
erstellt_am TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||||
geaendert_am TIMESTAMP WITH TIME ZONE NOT NULL
|
geaendert_am TIMESTAMP WITH TIME ZONE NOT NULL
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
CREATE TABLE IF NOT EXISTS rollen (
|
CREATE TABLE IF NOT EXISTS rollen (
|
||||||
id UUID PRIMARY KEY,
|
rolle_id UUID PRIMARY KEY,
|
||||||
|
id ULID UNIQUE NOT NULL,
|
||||||
rollenname VARCHAR NOT NULL,
|
rollenname VARCHAR NOT NULL,
|
||||||
erstellt_am TIMESTAMP WITH TIME ZONE NOT NULL,
|
erstellt_am TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||||
geaendert_am TIMESTAMP WITH TIME ZONE NOT NULL
|
geaendert_am TIMESTAMP WITH TIME ZONE NOT NULL
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ CREATE TABLE IF NOT EXISTS rollen_gruppen (
|
|||||||
CONSTRAINT pk_rollen_gruppen PRIMARY KEY (rolle_id, gruppe_id),
|
CONSTRAINT pk_rollen_gruppen PRIMARY KEY (rolle_id, gruppe_id),
|
||||||
|
|
||||||
CONSTRAINT fk_rollen_gruppen_gruppe FOREIGN KEY (gruppe_id)
|
CONSTRAINT fk_rollen_gruppen_gruppe FOREIGN KEY (gruppe_id)
|
||||||
REFERENCES gruppen (id) MATCH SIMPLE
|
REFERENCES gruppen (gruppe_id) MATCH SIMPLE
|
||||||
ON UPDATE CASCADE
|
ON UPDATE CASCADE
|
||||||
ON DELETE CASCADE,
|
ON DELETE CASCADE,
|
||||||
|
|
||||||
CONSTRAINT fk_rollen_gruppen_rolle FOREIGN KEY (rolle_id)
|
CONSTRAINT fk_rollen_gruppen_rolle FOREIGN KEY (rolle_id)
|
||||||
REFERENCES rollen (id) MATCH SIMPLE
|
REFERENCES rollen (rolle_id) MATCH SIMPLE
|
||||||
ON UPDATE CASCADE
|
ON UPDATE CASCADE
|
||||||
ON DELETE CASCADE
|
ON DELETE CASCADE
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
CREATE TABLE IF NOT EXISTS benutzer (
|
CREATE TABLE IF NOT EXISTS benutzer (
|
||||||
id UUID PRIMARY KEY,
|
benutzer_id UUID PRIMARY KEY,
|
||||||
|
id ULID UNIQUE NOT NULL,
|
||||||
kennung VARCHAR NOT NULL,
|
kennung VARCHAR NOT NULL,
|
||||||
nachname VARCHAR NOT NULL,
|
nachname VARCHAR NOT NULL,
|
||||||
vorname VARCHAR NOT NULL,
|
vorname VARCHAR NOT NULL,
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ CREATE TABLE IF NOT EXISTS benutzer_gruppen (
|
|||||||
CONSTRAINT pk_benutzer_gruppen PRIMARY KEY (benutzer_id, gruppe_id),
|
CONSTRAINT pk_benutzer_gruppen PRIMARY KEY (benutzer_id, gruppe_id),
|
||||||
|
|
||||||
CONSTRAINT fk_benutzer_gruppen_benutzer FOREIGN KEY (benutzer_id)
|
CONSTRAINT fk_benutzer_gruppen_benutzer FOREIGN KEY (benutzer_id)
|
||||||
REFERENCES benutzer (id) MATCH SIMPLE
|
REFERENCES benutzer (benutzer_id) MATCH SIMPLE
|
||||||
ON UPDATE CASCADE
|
ON UPDATE CASCADE
|
||||||
ON DELETE CASCADE,
|
ON DELETE CASCADE,
|
||||||
|
|
||||||
CONSTRAINT fk_benutzer_gruppen_gruppe FOREIGN KEY (gruppe_id)
|
CONSTRAINT fk_benutzer_gruppen_gruppe FOREIGN KEY (gruppe_id)
|
||||||
REFERENCES gruppen (id) MATCH SIMPLE
|
REFERENCES gruppen (gruppe_id) MATCH SIMPLE
|
||||||
ON UPDATE CASCADE
|
ON UPDATE CASCADE
|
||||||
ON DELETE CASCADE
|
ON DELETE CASCADE
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ CREATE TABLE IF NOT EXISTS benutzer_rollen (
|
|||||||
CONSTRAINT pk_benutzer_rollen PRIMARY KEY (benutzer_id, rolle_id),
|
CONSTRAINT pk_benutzer_rollen PRIMARY KEY (benutzer_id, rolle_id),
|
||||||
|
|
||||||
CONSTRAINT fk_benutzer_rollen_benutzer FOREIGN KEY (benutzer_id)
|
CONSTRAINT fk_benutzer_rollen_benutzer FOREIGN KEY (benutzer_id)
|
||||||
REFERENCES benutzer (id) MATCH SIMPLE
|
REFERENCES benutzer (benutzer_id) MATCH SIMPLE
|
||||||
ON UPDATE CASCADE
|
ON UPDATE CASCADE
|
||||||
ON DELETE CASCADE,
|
ON DELETE CASCADE,
|
||||||
|
|
||||||
CONSTRAINT fk_benutzer_rollen_rolle FOREIGN KEY (rolle_id)
|
CONSTRAINT fk_benutzer_rollen_rolle FOREIGN KEY (rolle_id)
|
||||||
REFERENCES rollen (id) MATCH SIMPLE
|
REFERENCES rollen (rolle_id) MATCH SIMPLE
|
||||||
ON UPDATE CASCADE
|
ON UPDATE CASCADE
|
||||||
ON DELETE CASCADE
|
ON DELETE CASCADE
|
||||||
)
|
)
|
||||||
|
|||||||
1
migrations/20260528200947_struktur.down.sql
Normal file
1
migrations/20260528200947_struktur.down.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE struktur;
|
||||||
8
migrations/20260528200947_struktur.up.sql
Normal file
8
migrations/20260528200947_struktur.up.sql
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS strukturen (
|
||||||
|
id UUID PRIMARY KEY,
|
||||||
|
parent_id UUID REFERENCES strukturen (id),
|
||||||
|
dienststelle VARCHAR NOT NULL,
|
||||||
|
dienststelle_abk VARCHAR NOT NULL,
|
||||||
|
slug TEXT NOT NULL,
|
||||||
|
pfad LTREE
|
||||||
|
);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
pub mod benutzer;
|
// pub mod benutzer;
|
||||||
pub mod gruppe;
|
pub mod gruppe;
|
||||||
pub mod liegenschaft;
|
pub mod liegenschaft;
|
||||||
pub mod rolle;
|
pub mod rolle;
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ use async_graphql::{ComplexObject, Context, FieldResult, SimpleObject};
|
|||||||
use crate::{
|
use crate::{
|
||||||
dataloader::LoaderContext,
|
dataloader::LoaderContext,
|
||||||
domain::{gruppe::model::Gruppe, rolle::model::Rolle},
|
domain::{gruppe::model::Gruppe, rolle::model::Rolle},
|
||||||
scalar::Id,
|
scalar::Ulid,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(sqlx::FromRow, SimpleObject)]
|
#[derive(sqlx::FromRow, SimpleObject)]
|
||||||
#[graphql(complex)]
|
#[graphql(complex)]
|
||||||
pub struct Benutzer {
|
pub struct Benutzer {
|
||||||
/// Die UUID eines Benutzers
|
/// Die ULid eines Benutzers
|
||||||
pub id: Id,
|
pub id: Ulid,
|
||||||
|
|
||||||
/// Die Kennung des Benutzers
|
/// Die Kennung des Benutzers
|
||||||
pub kennung: String,
|
pub kennung: String,
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
use crate::scalar::Id;
|
|
||||||
use async_graphql::InputObject;
|
use async_graphql::InputObject;
|
||||||
|
|
||||||
|
use crate::scalar::Ulid;
|
||||||
|
|
||||||
#[derive(InputObject)]
|
#[derive(InputObject)]
|
||||||
pub struct BenutzerCreateInput {
|
pub struct BenutzerCreateInput {
|
||||||
// #[graphql(validator(min_length = 6, max_length = 8))]
|
// #[graphql(validator(min_length = 6, max_length = 8))]
|
||||||
pub kennung: String,
|
pub kennung: String,
|
||||||
pub vorname: String,
|
pub vorname: String,
|
||||||
pub nachname: String,
|
pub nachname: String,
|
||||||
pub rollen: Option<Vec<Id>>,
|
pub rollen: Option<Vec<Ulid>>,
|
||||||
pub gruppen: Option<Vec<Id>>,
|
pub gruppen: Option<Vec<Ulid>>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use async_graphql::{ComplexObject, Enum, SimpleObject};
|
use async_graphql::{ComplexObject, Enum, SimpleObject};
|
||||||
use sqlx::Type;
|
use sqlx::Type;
|
||||||
|
|
||||||
use crate::scalar::{Id, Time};
|
use crate::scalar::{Time, Ulid};
|
||||||
|
|
||||||
/// Aus welcher Quelle die Gruppe stammt.
|
/// Aus welcher Quelle die Gruppe stammt.
|
||||||
#[derive(Enum, Clone, Debug, Eq, Copy, PartialEq, Type)]
|
#[derive(Enum, Clone, Debug, Eq, Copy, PartialEq, Type)]
|
||||||
@@ -21,7 +21,7 @@ pub enum Herkunft {
|
|||||||
#[graphql(complex)]
|
#[graphql(complex)]
|
||||||
pub struct GruppeAnsicht {
|
pub struct GruppeAnsicht {
|
||||||
/// Die UUID einer Gruppe
|
/// Die UUID einer Gruppe
|
||||||
pub id: Id,
|
pub id: Ulid,
|
||||||
|
|
||||||
/// Der Gruppenname
|
/// Der Gruppenname
|
||||||
pub gruppenname: String,
|
pub gruppenname: String,
|
||||||
|
|||||||
@@ -5,17 +5,17 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use crate::domain::gruppe::model::Gruppe;
|
use crate::domain::gruppe::model::Gruppe;
|
||||||
use crate::domain::gruppe::service::Service;
|
use crate::domain::gruppe::service::Service;
|
||||||
use crate::scalar::Id;
|
use crate::scalar::Ulid;
|
||||||
|
|
||||||
pub struct GruppenLoader {
|
pub struct GruppenLoader {
|
||||||
pub pool: sqlx::PgPool,
|
pub pool: sqlx::PgPool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Loader<Id> for GruppenLoader {
|
impl Loader<Ulid> for GruppenLoader {
|
||||||
type Value = Vec<Gruppe>;
|
type Value = Vec<Gruppe>;
|
||||||
type Error = Arc<sqlx::Error>;
|
type Error = Arc<sqlx::Error>;
|
||||||
|
|
||||||
async fn load(&self, keys: &[Id]) -> Result<HashMap<Id, Self::Value>, Self::Error> {
|
async fn load(&self, keys: &[Ulid]) -> Result<HashMap<Ulid, Self::Value>, Self::Error> {
|
||||||
let rows = Service::new(self.pool.clone())
|
let rows = Service::new(self.pool.clone())
|
||||||
.gruppe_dataloader(keys)
|
.gruppe_dataloader(keys)
|
||||||
.await?;
|
.await?;
|
||||||
|
|||||||
@@ -1,2 +1,6 @@
|
|||||||
pub mod gruppe;
|
pub mod gruppe;
|
||||||
pub use gruppe::Gruppe;
|
|
||||||
|
pub use gruppe::GruppeDataloader;
|
||||||
|
pub use gruppe::GruppeErstellen;
|
||||||
|
pub use gruppe::GruppeLoeschen;
|
||||||
|
pub use gruppe::GruppeUpdate;
|
||||||
|
|||||||
@@ -1,8 +1,30 @@
|
|||||||
use crate::scalar::{Id, Time};
|
use sqlx::FromRow;
|
||||||
|
|
||||||
pub struct Gruppe {
|
use crate::scalar::{Id, Time, Ulid};
|
||||||
pub id: Id,
|
|
||||||
|
pub struct GruppeErstellen {
|
||||||
|
pub gruppe_id: Id,
|
||||||
|
pub id: Ulid,
|
||||||
pub gruppenname: String,
|
pub gruppenname: String,
|
||||||
pub erstellt_am: Option<Time>,
|
pub erstellt_am: Time,
|
||||||
pub geaendert_am: Option<Time>,
|
pub geaendert_am: Time,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GruppeLoeschen {
|
||||||
|
pub id: Ulid,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GruppeUpdate {
|
||||||
|
pub id: Ulid,
|
||||||
|
pub gruppenname: String,
|
||||||
|
pub geaendert_am: Time,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, FromRow)]
|
||||||
|
pub struct GruppeDataloader {
|
||||||
|
pub r_ulid: Ulid,
|
||||||
|
pub g_ulid: Ulid,
|
||||||
|
pub gruppenname: String,
|
||||||
|
pub erstellt_am: Time,
|
||||||
|
pub geaendert_am: Time,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use async_graphql::{ComplexObject, SimpleObject};
|
use async_graphql::{ComplexObject, SimpleObject};
|
||||||
|
|
||||||
use crate::scalar::{Id, Time};
|
use crate::scalar::{Time, Ulid};
|
||||||
|
|
||||||
#[derive(sqlx::FromRow, SimpleObject, Clone, Debug)]
|
#[derive(sqlx::FromRow, SimpleObject, Clone, Debug)]
|
||||||
#[graphql(complex)]
|
#[graphql(complex)]
|
||||||
pub struct Gruppe {
|
pub struct Gruppe {
|
||||||
/// Die UUID einer Gruppe
|
/// Die UUID einer Gruppe
|
||||||
pub id: Id,
|
pub id: Ulid,
|
||||||
|
|
||||||
/// Der Gruppenname
|
/// Der Gruppenname
|
||||||
pub gruppenname: String,
|
pub gruppenname: String,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use async_graphql::InputObject;
|
use async_graphql::InputObject;
|
||||||
|
|
||||||
use crate::scalar::Id;
|
use crate::scalar::Ulid;
|
||||||
|
|
||||||
#[derive(InputObject)]
|
#[derive(InputObject)]
|
||||||
pub struct GruppeLoeschenInput {
|
pub struct GruppeLoeschenInput {
|
||||||
/// Die ID einer Gruppe
|
/// Die ULID einer Gruppe
|
||||||
pub id: Id,
|
pub id: Ulid,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::scalar::Id;
|
use crate::scalar::Ulid;
|
||||||
use async_graphql::InputObject;
|
use async_graphql::InputObject;
|
||||||
|
|
||||||
#[derive(InputObject)]
|
#[derive(InputObject)]
|
||||||
pub struct GruppeUpdateInput {
|
pub struct GruppeUpdateInput {
|
||||||
/// Die ID einer Gruppe
|
/// Die Ulid einer Gruppe
|
||||||
pub id: Id,
|
pub id: Ulid,
|
||||||
|
|
||||||
/// Der Name einer Gruppe
|
/// Der Name einer Gruppe
|
||||||
pub gruppenname: String,
|
pub gruppenname: String,
|
||||||
|
|||||||
@@ -1,48 +1,53 @@
|
|||||||
|
use itertools::Itertools;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
use super::Repository;
|
use super::Repository;
|
||||||
|
|
||||||
use crate::database::Queryer;
|
use crate::database::Queryer;
|
||||||
|
use crate::domain::gruppe::entity::GruppeDataloader;
|
||||||
use crate::domain::gruppe::model::Gruppe;
|
use crate::domain::gruppe::model::Gruppe;
|
||||||
use crate::scalar::Id;
|
use crate::scalar::Ulid;
|
||||||
|
|
||||||
impl Repository {
|
impl Repository {
|
||||||
pub async fn gruppe_dataloader<'c, C: Queryer<'c>>(
|
pub async fn gruppe_dataloader<'c, C: Queryer<'c>>(
|
||||||
&self,
|
&self,
|
||||||
db: C,
|
db: C,
|
||||||
keys: &[Id],
|
keys: &[Ulid],
|
||||||
) -> Result<HashMap<Id, Vec<Gruppe>>, Arc<sqlx::Error>> {
|
) -> Result<HashMap<Ulid, Vec<Gruppe>>, Arc<sqlx::Error>> {
|
||||||
let rows = sqlx::query!(
|
const QUERY: &str = r#"
|
||||||
r#"
|
SELECT
|
||||||
SELECT
|
rg.rolle_id as r_ulid,
|
||||||
rg.rolle_id,
|
g.id as g_ulid,
|
||||||
g.id,
|
g.gruppenname,
|
||||||
g.gruppenname,
|
g.erstellt_am,
|
||||||
g.erstellt_am,
|
g.geaendert_am
|
||||||
g.geaendert_am
|
FROM gruppen AS g
|
||||||
FROM gruppen AS g
|
LEFT JOIN rollen_gruppen AS rg ON g.gruppe_id = rg.gruppe_id
|
||||||
LEFT JOIN rollen_gruppen AS rg ON g.id = rg.gruppe_id
|
WHERE rg.rolle_id IN (
|
||||||
WHERE rg.rolle_id = ANY($1);
|
SELECT benutzer_id
|
||||||
"#,
|
FROM benutzer
|
||||||
keys
|
WHERE id = ANY($1)
|
||||||
)
|
);
|
||||||
.fetch_all(db)
|
"#;
|
||||||
.await?
|
|
||||||
.into_iter()
|
let rows = sqlx::query_as::<_, GruppeDataloader>(QUERY)
|
||||||
.map(|row| {
|
.bind(keys)
|
||||||
(
|
.fetch_all(db)
|
||||||
row.rolle_id,
|
.await?
|
||||||
Gruppe {
|
.into_iter()
|
||||||
id: row.id,
|
.map(|row| {
|
||||||
gruppenname: row.gruppenname,
|
(
|
||||||
erstellt_am: row.erstellt_am,
|
row.r_ulid,
|
||||||
geaendert_am: row.geaendert_am,
|
Gruppe {
|
||||||
},
|
id: row.g_ulid,
|
||||||
)
|
gruppenname: row.gruppenname,
|
||||||
})
|
erstellt_am: row.erstellt_am,
|
||||||
.into_group_map();
|
geaendert_am: row.geaendert_am,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.into_group_map();
|
||||||
|
|
||||||
Ok(rows)
|
Ok(rows)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,19 +8,20 @@ impl Repository {
|
|||||||
pub async fn gruppe_erstellen<'c, C: Queryer<'c>>(
|
pub async fn gruppe_erstellen<'c, C: Queryer<'c>>(
|
||||||
&self,
|
&self,
|
||||||
db: C,
|
db: C,
|
||||||
gruppe: &entity::Gruppe,
|
gruppe: &entity::GruppeErstellen,
|
||||||
) -> Result<model::Gruppe, Error> {
|
) -> Result<model::Gruppe, Error> {
|
||||||
const QUERY: &str = r#"
|
const QUERY: &str = r#"
|
||||||
INSERT INTO gruppen (id, erstellt_am, geaendert_am, gruppenname) VALUES (
|
INSERT INTO gruppen (gruppe_id, id, gruppenname, erstellt_am, geaendert_am) VALUES (
|
||||||
$1, $2, $3, $4
|
$1, $2, $3, $4, $5
|
||||||
) RETURNING id, erstellt_am, geaendert_am, gruppenname;
|
) RETURNING id, gruppenname, erstellt_am, geaendert_am;
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let gruppe = sqlx::query_as::<_, model::Gruppe>(QUERY)
|
let gruppe = sqlx::query_as::<_, model::Gruppe>(QUERY)
|
||||||
|
.bind(gruppe.gruppe_id)
|
||||||
.bind(gruppe.id)
|
.bind(gruppe.id)
|
||||||
|
.bind(&gruppe.gruppenname)
|
||||||
.bind(gruppe.erstellt_am)
|
.bind(gruppe.erstellt_am)
|
||||||
.bind(gruppe.geaendert_am)
|
.bind(gruppe.geaendert_am)
|
||||||
.bind(&gruppe.gruppenname)
|
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ impl Repository {
|
|||||||
pub async fn gruppe_loeschen<'c, C: Queryer<'c>>(
|
pub async fn gruppe_loeschen<'c, C: Queryer<'c>>(
|
||||||
&self,
|
&self,
|
||||||
db: C,
|
db: C,
|
||||||
gruppe: &entity::Gruppe,
|
gruppe: &entity::GruppeLoeschen,
|
||||||
) -> Result<model::Gruppe, Error> {
|
) -> Result<model::Gruppe, Error> {
|
||||||
const QUERY: &str = r#"
|
const QUERY: &str = r#"
|
||||||
DELETE FROM gruppen WHERE id=$1 RETURNING id, gruppenname, erstellt_am, geaendert_am;
|
DELETE FROM gruppen WHERE id=$1 RETURNING id, gruppenname, erstellt_am, geaendert_am;
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ impl Repository {
|
|||||||
pub async fn gruppe_update<'c, C: Queryer<'c>>(
|
pub async fn gruppe_update<'c, C: Queryer<'c>>(
|
||||||
&self,
|
&self,
|
||||||
db: C,
|
db: C,
|
||||||
gruppe: &entity::Gruppe,
|
gruppe: &entity::GruppeUpdate,
|
||||||
) -> Result<model::Gruppe, Error> {
|
) -> Result<model::Gruppe, Error> {
|
||||||
const QUERY: &str = r#"
|
const QUERY: &str = r#"
|
||||||
UPDATE gruppen
|
UPDATE gruppen
|
||||||
SET geaendert_am = $2, ruppenname = $3 WHERE gruppeid = $1
|
SET geaendert_am = $2, ruppenname = $3 WHERE gruppeid = $1
|
||||||
RETURNING id, geaendert_am, erstellt_am, gruppenname;
|
RETURNING id, gruppenname, geaendert_am, erstellt_am;
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let gruppe = sqlx::query_as::<_, model::Gruppe>(QUERY)
|
let gruppe = sqlx::query_as::<_, model::Gruppe>(QUERY)
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
use crate::{domain::gruppe::model::Gruppe, scalar::Id};
|
use crate::{domain::gruppe::model::Gruppe, scalar::Ulid};
|
||||||
|
|
||||||
use super::Service;
|
use super::Service;
|
||||||
|
|
||||||
impl Service {
|
impl Service {
|
||||||
pub async fn gruppe_dataloader(
|
pub async fn gruppe_dataloader(
|
||||||
&self,
|
&self,
|
||||||
keys: &[Id],
|
keys: &[Ulid],
|
||||||
) -> Result<HashMap<Id, Vec<Gruppe>>, Arc<sqlx::Error>> {
|
) -> Result<HashMap<Ulid, Vec<Gruppe>>, Arc<sqlx::Error>> {
|
||||||
let gruppen_dataloader = self.repo.gruppe_dataloader(&self.db, keys).await?;
|
let gruppen_dataloader = self.repo.gruppe_dataloader(&self.db, keys).await?;
|
||||||
Ok(gruppen_dataloader)
|
Ok(gruppen_dataloader)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,25 @@
|
|||||||
|
use super::Service;
|
||||||
|
use crate::{
|
||||||
|
domain::gruppe::{
|
||||||
|
entity,
|
||||||
|
model::{self, GruppeErstelleInput},
|
||||||
|
},
|
||||||
|
scalar::Ulid,
|
||||||
|
};
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use ulid::Ulid;
|
|
||||||
|
|
||||||
use super::Service;
|
|
||||||
use crate::domain::gruppe::{
|
|
||||||
entity,
|
|
||||||
model::{self, GruppeErstelleInput},
|
|
||||||
};
|
|
||||||
|
|
||||||
impl Service {
|
impl Service {
|
||||||
pub async fn gruppe_erstellen(
|
pub async fn gruppe_erstellen(
|
||||||
&self,
|
&self,
|
||||||
input: GruppeErstelleInput,
|
input: GruppeErstelleInput,
|
||||||
) -> Result<model::Gruppe, Error> {
|
) -> Result<model::Gruppe, Error> {
|
||||||
let gruppe_input = entity::Gruppe {
|
let gruppe_input = entity::GruppeErstellen {
|
||||||
id: Ulid::new().into(),
|
gruppe_id: ulid::Ulid::new().into(),
|
||||||
|
id: Ulid(ulid::Ulid::new().into()),
|
||||||
gruppenname: input.gruppenname,
|
gruppenname: input.gruppenname,
|
||||||
erstellt_am: Some(Utc::now()),
|
erstellt_am: Utc::now(),
|
||||||
geaendert_am: Some(Utc::now()),
|
geaendert_am: Utc::now(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let gruppe = self.repo.gruppe_erstellen(&self.db, &gruppe_input).await?;
|
let gruppe = self.repo.gruppe_erstellen(&self.db, &gruppe_input).await?;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use chrono::Utc;
|
|
||||||
|
|
||||||
use super::Service;
|
use super::Service;
|
||||||
use crate::domain::gruppe::{
|
use crate::domain::gruppe::{
|
||||||
@@ -12,12 +11,7 @@ impl Service {
|
|||||||
&self,
|
&self,
|
||||||
input: GruppeLoeschenInput,
|
input: GruppeLoeschenInput,
|
||||||
) -> Result<model::Gruppe, Error> {
|
) -> Result<model::Gruppe, Error> {
|
||||||
let gruppe_input = entity::Gruppe {
|
let gruppe_input = entity::GruppeLoeschen { id: input.id };
|
||||||
id: input.id,
|
|
||||||
gruppenname: String::new(),
|
|
||||||
erstellt_am: None,
|
|
||||||
geaendert_am: Some(Utc::now()),
|
|
||||||
};
|
|
||||||
|
|
||||||
let gruppe = self.repo.gruppe_loeschen(&self.db, &gruppe_input).await?;
|
let gruppe = self.repo.gruppe_loeschen(&self.db, &gruppe_input).await?;
|
||||||
Ok(gruppe)
|
Ok(gruppe)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use ulid::Ulid;
|
|
||||||
|
|
||||||
use super::Service;
|
use super::Service;
|
||||||
use crate::domain::gruppe::{
|
use crate::domain::gruppe::{
|
||||||
@@ -10,11 +9,10 @@ use crate::domain::gruppe::{
|
|||||||
|
|
||||||
impl Service {
|
impl Service {
|
||||||
pub async fn gruppe_update(&self, input: GruppeUpdateInput) -> Result<model::Gruppe, Error> {
|
pub async fn gruppe_update(&self, input: GruppeUpdateInput) -> Result<model::Gruppe, Error> {
|
||||||
let gruppe_input = entity::Gruppe {
|
let gruppe_input = entity::GruppeUpdate {
|
||||||
id: Ulid::new().into(),
|
id: input.id,
|
||||||
gruppenname: input.gruppenname,
|
gruppenname: input.gruppenname,
|
||||||
erstellt_am: None,
|
geaendert_am: Utc::now(),
|
||||||
geaendert_am: Some(Utc::now()),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let gruppe = self.repo.gruppe_update(&self.db, &gruppe_input).await?;
|
let gruppe = self.repo.gruppe_update(&self.db, &gruppe_input).await?;
|
||||||
|
|||||||
@@ -1,51 +1,23 @@
|
|||||||
use async_graphql::dataloader::*;
|
use async_graphql::dataloader::Loader;
|
||||||
use async_graphql::*;
|
|
||||||
use itertools::Itertools;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::domain::rolle::model::Rolle;
|
use crate::domain::rolle::model::Rolle;
|
||||||
use crate::scalar::Id;
|
use crate::domain::rolle::service::Service;
|
||||||
|
use crate::scalar::Ulid;
|
||||||
|
|
||||||
pub struct RollenLoader {
|
pub struct RollenLoader {
|
||||||
pub pool: sqlx::PgPool,
|
pub pool: sqlx::PgPool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Loader<Id> for RollenLoader {
|
impl Loader<Ulid> for RollenLoader {
|
||||||
type Value = Vec<Rolle>;
|
type Value = Vec<Rolle>;
|
||||||
type Error = Arc<sqlx::Error>;
|
type Error = Arc<sqlx::Error>;
|
||||||
|
|
||||||
async fn load(&self, keys: &[Id]) -> Result<HashMap<Id, Self::Value>, Self::Error> {
|
async fn load(&self, keys: &[Ulid]) -> Result<HashMap<Ulid, Self::Value>, Self::Error> {
|
||||||
let rows = sqlx::query!(
|
let rows = Service::new(self.pool.clone())
|
||||||
r#"
|
.rolle_dataloader(keys)
|
||||||
SELECT
|
.await?;
|
||||||
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)
|
Ok(rows)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,6 @@
|
|||||||
pub mod rolle;
|
pub mod rolle;
|
||||||
pub use rolle::Rolle;
|
|
||||||
|
pub use rolle::RolleErstellen;
|
||||||
|
pub use rolle::RolleLoeschen;
|
||||||
|
pub use rolle::RolleRow;
|
||||||
|
pub use rolle::RolleUpdate;
|
||||||
|
|||||||
@@ -1,8 +1,30 @@
|
|||||||
use crate::scalar::{Id, Time};
|
use sqlx::FromRow;
|
||||||
|
|
||||||
pub struct Rolle {
|
use crate::scalar::{Id, Time, Ulid};
|
||||||
pub id: Id,
|
|
||||||
|
pub struct RolleErstellen {
|
||||||
|
pub rolle_id: Id,
|
||||||
|
pub id: Ulid,
|
||||||
pub rollenname: String,
|
pub rollenname: String,
|
||||||
pub erstellt_am: Option<Time>,
|
pub erstellt_am: Time,
|
||||||
pub geaendert_am: Option<Time>,
|
pub geaendert_am: Time,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RolleLoeschen {
|
||||||
|
pub id: Ulid,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RolleUpdate {
|
||||||
|
pub id: Ulid,
|
||||||
|
pub rollenname: String,
|
||||||
|
pub geaendert_am: Time,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, FromRow)]
|
||||||
|
pub struct RolleRow {
|
||||||
|
pub b_ulid: Ulid,
|
||||||
|
pub r_ulid: Ulid,
|
||||||
|
pub rollenname: String,
|
||||||
|
pub erstellt_am: Time,
|
||||||
|
pub geaendert_am: Time,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ use async_graphql::{ComplexObject, Context, FieldResult, SimpleObject};
|
|||||||
use crate::{
|
use crate::{
|
||||||
dataloader::LoaderContext,
|
dataloader::LoaderContext,
|
||||||
domain::gruppe::model::Gruppe,
|
domain::gruppe::model::Gruppe,
|
||||||
scalar::{Id, Time},
|
scalar::{Time, Ulid},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Um die Administration zu erleichtern werden Gruppen in die Rollen hinzugefuegt
|
/// Um die Administration zu erleichtern werden Gruppen in die Rollen hinzugefuegt
|
||||||
#[derive(sqlx::FromRow, SimpleObject, Debug, Clone)]
|
#[derive(sqlx::FromRow, SimpleObject, Debug, Clone)]
|
||||||
#[graphql(complex)]
|
#[graphql(complex)]
|
||||||
pub struct Rolle {
|
pub struct Rolle {
|
||||||
/// Die uuid einer Rolle
|
/// Die ULID einer Rolle
|
||||||
pub id: Id,
|
pub id: Ulid,
|
||||||
|
|
||||||
/// Der Rollenname
|
/// Der Rollenname
|
||||||
pub rollenname: String,
|
pub rollenname: String,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use async_graphql::InputObject;
|
use async_graphql::InputObject;
|
||||||
|
|
||||||
use crate::scalar::Id;
|
use crate::scalar::Ulid;
|
||||||
|
|
||||||
#[derive(InputObject)]
|
#[derive(InputObject)]
|
||||||
pub struct RolleLoeschenInput {
|
pub struct RolleLoeschenInput {
|
||||||
/// Die ID einer Rolle
|
/// Die Ulid einer Rolle
|
||||||
pub id: Id,
|
pub id: Ulid,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::scalar::Id;
|
use crate::scalar::Ulid;
|
||||||
use async_graphql::InputObject;
|
use async_graphql::InputObject;
|
||||||
|
|
||||||
#[derive(InputObject)]
|
#[derive(InputObject)]
|
||||||
pub struct RolleUpdateInput {
|
pub struct RolleUpdateInput {
|
||||||
/// Die ID einer Rolle
|
/// Die Ulid einer Rolle
|
||||||
pub id: Id,
|
pub id: Ulid,
|
||||||
|
|
||||||
/// Der Name einer Rolle
|
/// Der Name einer Rolle
|
||||||
pub rollenname: String,
|
pub rollenname: String,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use async_graphql::{Context, FieldResult, Object};
|
use async_graphql::{Context, FieldResult, Object};
|
||||||
use sqlx::postgres::PgPool;
|
use sqlx::postgres::PgPool;
|
||||||
|
|
||||||
use crate::domain::rolle::model::Rolle;
|
use crate::domain::rolle::{model::Rolle, service::Service};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct RolleQuery {}
|
pub struct RolleQuery {}
|
||||||
@@ -15,11 +15,8 @@ impl RolleQuery {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
async fn rollen(&self, ctx: &Context<'_>) -> FieldResult<Vec<Rolle>> {
|
async fn rollen(&self, ctx: &Context<'_>) -> FieldResult<Vec<Rolle>> {
|
||||||
let pool = ctx.data::<PgPool>()?;
|
let pool = ctx.data::<PgPool>()?.clone();
|
||||||
|
let rollen = Service::new(pool).rolle_alle().await?;
|
||||||
let rollen = sqlx::query_as!(Rolle, "SELECT * FROM rollen")
|
|
||||||
.fetch_all(pool)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(rollen)
|
Ok(rollen)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
mod find_all_rolle;
|
mod find_all_rolle;
|
||||||
mod find_rolle_by_id;
|
mod find_rolle_by_id;
|
||||||
|
mod rolle_alle;
|
||||||
|
mod rolle_dataloader;
|
||||||
mod rolle_erstellen;
|
mod rolle_erstellen;
|
||||||
mod rolle_loeschen;
|
mod rolle_loeschen;
|
||||||
mod rolle_update;
|
mod rolle_update;
|
||||||
mod rollen_dataloader;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Repository {}
|
pub struct Repository {}
|
||||||
@@ -13,6 +14,7 @@ impl Repository {
|
|||||||
Repository {}
|
Repository {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Repository {
|
impl Default for Repository {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
|
|||||||
17
src/domain/rolle/repository/rolle_alle.rs
Normal file
17
src/domain/rolle/repository/rolle_alle.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
use anyhow::Error;
|
||||||
|
|
||||||
|
use super::Repository;
|
||||||
|
use crate::{database::Queryer, domain::rolle::model};
|
||||||
|
|
||||||
|
impl Repository {
|
||||||
|
pub async fn rolle_alle<'c, C: Queryer<'c>>(&self, db: C) -> Result<Vec<model::Rolle>, Error> {
|
||||||
|
const QUERY: &str = r#"
|
||||||
|
SELECT id, rollenname, erstellt_am, geaendert_am FROM rollen
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let rollen = sqlx::query_as::<_, model::Rolle>(QUERY)
|
||||||
|
.fetch_all(db)
|
||||||
|
.await?;
|
||||||
|
Ok(rollen)
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/domain/rolle/repository/rolle_dataloader.rs
Normal file
55
src/domain/rolle/repository/rolle_dataloader.rs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
use itertools::Itertools;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use super::Repository;
|
||||||
|
|
||||||
|
use crate::database::Queryer;
|
||||||
|
use crate::domain::rolle::entity::RolleRow;
|
||||||
|
use crate::domain::rolle::model;
|
||||||
|
use crate::scalar::Ulid;
|
||||||
|
|
||||||
|
impl Repository {
|
||||||
|
pub async fn rolle_dataloader<'c, C: Queryer<'c>>(
|
||||||
|
&self,
|
||||||
|
db: C,
|
||||||
|
keys: &[Ulid],
|
||||||
|
) -> Result<HashMap<Ulid, Vec<model::Rolle>>, Arc<sqlx::Error>> {
|
||||||
|
const QUERY: &str = r#"
|
||||||
|
SELECT
|
||||||
|
b.id as b_ulid,
|
||||||
|
r.id as r_ulid,
|
||||||
|
r.rollenname,
|
||||||
|
r.erstellt_am,
|
||||||
|
r.geaendert_am
|
||||||
|
FROM rollen AS r
|
||||||
|
LEFT JOIN benutzer_rollen AS br ON r.rolle_id = br.rolle_id
|
||||||
|
LEFT JOIN benutzer AS b ON br.benutzer_id = b.benutzer_id
|
||||||
|
WHERE br.benutzer_id IN (
|
||||||
|
SELECT benutzer_id
|
||||||
|
FROM benutzer
|
||||||
|
WHERE id = ANY($1)
|
||||||
|
)
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let rows = sqlx::query_as::<_, RolleRow>(QUERY)
|
||||||
|
.bind(keys)
|
||||||
|
.fetch_all(db)
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.map(|row| {
|
||||||
|
(
|
||||||
|
row.b_ulid,
|
||||||
|
model::Rolle {
|
||||||
|
id: row.r_ulid,
|
||||||
|
rollenname: row.rollenname,
|
||||||
|
erstellt_am: row.erstellt_am,
|
||||||
|
geaendert_am: row.geaendert_am,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.into_group_map();
|
||||||
|
|
||||||
|
Ok(rows)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,19 +8,20 @@ impl Repository {
|
|||||||
pub async fn rolle_erstellen<'c, C: Queryer<'c>>(
|
pub async fn rolle_erstellen<'c, C: Queryer<'c>>(
|
||||||
&self,
|
&self,
|
||||||
db: C,
|
db: C,
|
||||||
rolle: &entity::Rolle,
|
rolle: &entity::RolleErstellen,
|
||||||
) -> Result<model::Rolle, Error> {
|
) -> Result<model::Rolle, Error> {
|
||||||
const QUERY: &str = r#"
|
const QUERY: &str = r#"
|
||||||
INSERT INTO rollen (id, erstellt_am, geaendert_am, rollenname) VALUES (
|
INSERT INTO rollen (rolle_id, id, rollenname, erstellt_am, geaendert_am) VALUES (
|
||||||
$1, $2, $3, $4
|
$1, $2, $3, $4, $5
|
||||||
) RETURNING id, erstellt_am, geaendert_am, rollenname
|
) RETURNING id, rollenname, erstellt_am, geaendert_am
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let rolle = sqlx::query_as::<_, model::Rolle>(QUERY)
|
let rolle = sqlx::query_as::<_, model::Rolle>(QUERY)
|
||||||
|
.bind(rolle.rolle_id)
|
||||||
.bind(rolle.id)
|
.bind(rolle.id)
|
||||||
|
.bind(&rolle.rollenname)
|
||||||
.bind(rolle.erstellt_am)
|
.bind(rolle.erstellt_am)
|
||||||
.bind(rolle.geaendert_am)
|
.bind(rolle.geaendert_am)
|
||||||
.bind(&rolle.rollenname)
|
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ impl Repository {
|
|||||||
pub async fn rolle_loeschen<'c, C: Queryer<'c>>(
|
pub async fn rolle_loeschen<'c, C: Queryer<'c>>(
|
||||||
&self,
|
&self,
|
||||||
db: C,
|
db: C,
|
||||||
rolle: &entity::Rolle,
|
rolle: &entity::RolleLoeschen,
|
||||||
) -> Result<model::Rolle, Error> {
|
) -> Result<model::Rolle, Error> {
|
||||||
const QUERY: &str = r#"
|
const QUERY: &str = r#"
|
||||||
DELETE FROM rollen WHERE id=$1 RETURNING id, rollenname, erstellt_am, geaendert_am;
|
DELETE FROM rollen WHERE id=$1 RETURNING id, rollenname, erstellt_am, geaendert_am;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ impl Repository {
|
|||||||
pub async fn rolle_update<'c, C: Queryer<'c>>(
|
pub async fn rolle_update<'c, C: Queryer<'c>>(
|
||||||
&self,
|
&self,
|
||||||
db: C,
|
db: C,
|
||||||
rolle: &entity::Rolle,
|
rolle: &entity::RolleUpdate,
|
||||||
) -> Result<model::Rolle, Error> {
|
) -> Result<model::Rolle, Error> {
|
||||||
const QUERY: &str = r#"
|
const QUERY: &str = r#"
|
||||||
UPDATE rollen
|
UPDATE rollen
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
mod rolle_alle;
|
||||||
|
mod rolle_dataloader;
|
||||||
mod rolle_erstellen;
|
mod rolle_erstellen;
|
||||||
mod rolle_loeschen;
|
mod rolle_loeschen;
|
||||||
mod rolle_update;
|
mod rolle_update;
|
||||||
|
|||||||
12
src/domain/rolle/service/rolle_alle.rs
Normal file
12
src/domain/rolle/service/rolle_alle.rs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
use anyhow::Error;
|
||||||
|
|
||||||
|
use crate::domain::rolle::model;
|
||||||
|
|
||||||
|
use super::Service;
|
||||||
|
|
||||||
|
impl Service {
|
||||||
|
pub async fn rolle_alle(&self) -> Result<Vec<model::Rolle>, Error> {
|
||||||
|
let typen = self.repo.rolle_alle(&self.db).await?;
|
||||||
|
Ok(typen)
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/domain/rolle/service/rolle_dataloader.rs
Normal file
15
src/domain/rolle/service/rolle_dataloader.rs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
|
use crate::{domain::rolle::model, scalar::Ulid};
|
||||||
|
|
||||||
|
use super::Service;
|
||||||
|
|
||||||
|
impl Service {
|
||||||
|
pub async fn rolle_dataloader(
|
||||||
|
&self,
|
||||||
|
keys: &[Ulid],
|
||||||
|
) -> Result<HashMap<Ulid, Vec<model::Rolle>>, Arc<sqlx::Error>> {
|
||||||
|
let typen = self.repo.rolle_dataloader(&self.db, keys).await?;
|
||||||
|
Ok(typen)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,23 @@
|
|||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use ulid::Ulid;
|
|
||||||
|
|
||||||
use super::Service;
|
use super::Service;
|
||||||
use crate::domain::rolle::{
|
use crate::{
|
||||||
entity,
|
domain::rolle::{
|
||||||
model::{self, RolleErstelleInput},
|
entity,
|
||||||
|
model::{self, RolleErstelleInput},
|
||||||
|
},
|
||||||
|
scalar::Ulid,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl Service {
|
impl Service {
|
||||||
pub async fn rolle_erstellen(&self, input: RolleErstelleInput) -> Result<model::Rolle, Error> {
|
pub async fn rolle_erstellen(&self, input: RolleErstelleInput) -> Result<model::Rolle, Error> {
|
||||||
let rolle_input = entity::Rolle {
|
let rolle_input = entity::RolleErstellen {
|
||||||
id: Ulid::new().into(),
|
rolle_id: ulid::Ulid::new().into(),
|
||||||
|
id: Ulid(ulid::Ulid::new()),
|
||||||
rollenname: input.rollenname,
|
rollenname: input.rollenname,
|
||||||
erstellt_am: Some(Utc::now()),
|
erstellt_am: Utc::now(),
|
||||||
geaendert_am: Some(Utc::now()),
|
geaendert_am: Utc::now(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let rolle = self.repo.rolle_erstellen(&self.db, &rolle_input).await?;
|
let rolle = self.repo.rolle_erstellen(&self.db, &rolle_input).await?;
|
||||||
|
|||||||
@@ -8,12 +8,7 @@ use crate::domain::rolle::{
|
|||||||
|
|
||||||
impl Service {
|
impl Service {
|
||||||
pub async fn rolle_loeschen(&self, input: RolleLoeschenInput) -> Result<model::Rolle, Error> {
|
pub async fn rolle_loeschen(&self, input: RolleLoeschenInput) -> Result<model::Rolle, Error> {
|
||||||
let rolle_input = entity::Rolle {
|
let rolle_input = entity::RolleLoeschen { id: input.id };
|
||||||
id: input.id,
|
|
||||||
rollenname: String::new(),
|
|
||||||
erstellt_am: None,
|
|
||||||
geaendert_am: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let deleted = self.repo.rolle_loeschen(&self.db, &rolle_input).await?;
|
let deleted = self.repo.rolle_loeschen(&self.db, &rolle_input).await?;
|
||||||
Ok(deleted)
|
Ok(deleted)
|
||||||
|
|||||||
@@ -9,11 +9,10 @@ use crate::domain::rolle::{
|
|||||||
|
|
||||||
impl Service {
|
impl Service {
|
||||||
pub async fn rolle_update(&self, input: RolleUpdateInput) -> Result<model::Rolle, Error> {
|
pub async fn rolle_update(&self, input: RolleUpdateInput) -> Result<model::Rolle, Error> {
|
||||||
let rolle_input = entity::Rolle {
|
let rolle_input = entity::RolleUpdate {
|
||||||
id: input.id,
|
id: input.id,
|
||||||
rollenname: input.rollenname,
|
rollenname: input.rollenname,
|
||||||
erstellt_am: None,
|
geaendert_am: Utc::now(),
|
||||||
geaendert_am: Some(Utc::now()),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let rolle = self.repo.rolle_update(&self.db, &rolle_input).await?;
|
let rolle = self.repo.rolle_update(&self.db, &rolle_input).await?;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
pub mod typ;
|
pub mod typ;
|
||||||
|
|
||||||
// pub use typ::Typ;
|
|
||||||
pub use typ::TypErstellen;
|
pub use typ::TypErstellen;
|
||||||
pub use typ::TypLoeschen;
|
pub use typ::TypLoeschen;
|
||||||
pub use typ::TypUpdate;
|
pub use typ::TypUpdate;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use sqlx::{FromRow, PgPool};
|
use sqlx::{FromRow, PgPool};
|
||||||
use ulid::Ulid;
|
use ulid::Ulid;
|
||||||
|
|
||||||
use crate::scalar::Id;
|
use crate::scalar::{Id, Time};
|
||||||
|
|
||||||
#[derive(SimpleObject, Debug, FromRow, Deserialize, Serialize, sqlx::Type)]
|
#[derive(SimpleObject, Debug, FromRow, Deserialize, Serialize, sqlx::Type)]
|
||||||
pub struct Hersteller {
|
pub struct Hersteller {
|
||||||
@@ -12,7 +12,13 @@ pub struct Hersteller {
|
|||||||
pub id: Id,
|
pub id: Id,
|
||||||
|
|
||||||
/// Der Name eines Herstellers
|
/// Der Name eines Herstellers
|
||||||
herstellername: String,
|
pub herstellername: String,
|
||||||
|
|
||||||
|
/// Wann die Rolle erstellt wurde
|
||||||
|
pub erstellt_am: Time,
|
||||||
|
|
||||||
|
/// Wann die Rolle geaendert wurde
|
||||||
|
pub geaendert_am: Time,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(InputObject, Debug)]
|
#[derive(InputObject, Debug)]
|
||||||
@@ -40,9 +46,12 @@ impl Hersteller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn read_all(pool: &PgPool) -> Result<Vec<Hersteller>> {
|
pub async fn read_all(pool: &PgPool) -> Result<Vec<Hersteller>> {
|
||||||
let rows = sqlx::query_as!(Hersteller, "SELECT id, herstellername FROM hersteller")
|
let rows = sqlx::query_as!(
|
||||||
.fetch_all(pool)
|
Hersteller,
|
||||||
.await?;
|
"SELECT id, herstellername, erstellt_am, geaendert_am FROM hersteller"
|
||||||
|
)
|
||||||
|
.fetch_all(pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(rows)
|
Ok(rows)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
pub mod benutzer;
|
// pub mod benutzer;
|
||||||
pub mod gruppe;
|
pub mod gruppe;
|
||||||
// pub mod hersteller;
|
// pub mod hersteller;
|
||||||
// pub mod modell;
|
// pub mod modell;
|
||||||
@@ -14,7 +14,7 @@ pub struct Mutation(
|
|||||||
TypMutation,
|
TypMutation,
|
||||||
// hersteller::HerstellerMutation,
|
// hersteller::HerstellerMutation,
|
||||||
// modell::ModellMutation,
|
// modell::ModellMutation,
|
||||||
benutzer::BenutzerMutation,
|
// benutzer::BenutzerMutation,
|
||||||
gruppe::GruppeMutation,
|
gruppe::GruppeMutation,
|
||||||
rolle::RolleMutation,
|
rolle::RolleMutation,
|
||||||
liegenschaft::LiegenschaftMutation,
|
liegenschaft::LiegenschaftMutation,
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
// pub mod hersteller;
|
// pub mod hersteller;
|
||||||
// pub mod modell;
|
// pub mod modell;
|
||||||
use crate::domain::{
|
use crate::domain::{
|
||||||
benutzer::queries::benutzer, gruppe::queries::gruppe, liegenschaft::queries::liegenschaft,
|
// benutzer::queries::benutzer,
|
||||||
rolle::queries::rolle, typ::queries::typ::TypQuery,
|
gruppe::queries::gruppe,
|
||||||
|
liegenschaft::queries::liegenschaft,
|
||||||
|
rolle::queries::rolle,
|
||||||
|
typ::queries::typ::TypQuery,
|
||||||
};
|
};
|
||||||
|
|
||||||
use async_graphql::MergedObject;
|
use async_graphql::MergedObject;
|
||||||
@@ -10,7 +13,7 @@ use async_graphql::MergedObject;
|
|||||||
#[derive(MergedObject, Default)]
|
#[derive(MergedObject, Default)]
|
||||||
pub struct Query(
|
pub struct Query(
|
||||||
TypQuery,
|
TypQuery,
|
||||||
benutzer::BenutzerQuery,
|
// benutzer::BenutzerQuery,
|
||||||
rolle::RolleQuery,
|
rolle::RolleQuery,
|
||||||
gruppe::GruppeQuery,
|
gruppe::GruppeQuery,
|
||||||
liegenschaft::LiegenschaftQuery, // modell::ModellQuery,
|
liegenschaft::LiegenschaftQuery, // modell::ModellQuery,
|
||||||
|
|||||||
@@ -1,67 +1,26 @@
|
|||||||
use async_graphql::*;
|
use async_graphql::*;
|
||||||
/// It is easier to track each type alias if this file is located on the top-level directory (here)
|
use sqlx::{
|
||||||
/// than in each domain. Also, separating them will create a lot of duplicate code.
|
postgres::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueRef},
|
||||||
use uuid::Uuid;
|
Decode, Encode, Postgres, Type,
|
||||||
|
};
|
||||||
|
use ulid::Ulid as UlidPrimitive;
|
||||||
|
|
||||||
pub type Time = chrono::DateTime<chrono::Utc>;
|
pub type Time = chrono::DateTime<chrono::Utc>;
|
||||||
|
|
||||||
/// The ID scalar type represents a unique identifier, often used to refetch an object or as key for a cache.
|
/// The ID scalar type represents a unique identifier, often used to refetch an object or as key for a cache.
|
||||||
/// The ID type appears in a JSON response as a String; however, it is not intended to be human-readable.
|
/// The ID type appears in a JSON response as a String; however, it is not intended to be human-readable.
|
||||||
/// When expected as an input type, any string (such as "4") or integer (such as 4) input value will be accepted as an ID.
|
/// When expected as an input type, any string (such as "4") or integer (such as 4) input value will be accepted as an ID.
|
||||||
pub type Id = Uuid;
|
pub type Id = uuid::Uuid;
|
||||||
|
|
||||||
// pub type Ulid = String;
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Ulid(pub UlidPrimitive);
|
||||||
// pub type Ulid = ulid::Ulid;
|
|
||||||
|
|
||||||
// #[derive(Clone, Copy, Eq, PartialEq)]
|
|
||||||
// pub struct Ulid(pub ulid::Ulid);
|
|
||||||
//
|
|
||||||
// /// The ULID scalar type represents a Universally Unique Lexicographically Sortable Identifier as defined by the ULID specification.
|
|
||||||
// /// ULIDs are 26-character strings that are URL-safe, case-insensitive, and lexicographically sortable,
|
|
||||||
// /// making them ideal for distributed systems requiring time-ordered unique identifiers.
|
|
||||||
// #[Scalar]
|
|
||||||
// impl ScalarType for Ulid {
|
|
||||||
// fn parse(value: Value) -> InputValueResult<Self> {
|
|
||||||
// match value {
|
|
||||||
// Value::String(s) => {
|
|
||||||
// let ulid = ulid::Ulid::from_string(&s).map_err(InputValueError::custom)?;
|
|
||||||
// Ok(Ulid(ulid))
|
|
||||||
// }
|
|
||||||
// _ => Err(InputValueError::expected_type(value)),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fn to_value(&self) -> Value {
|
|
||||||
// Value::String(self.0.to_string())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl fmt::Display for Ulid {
|
|
||||||
// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
// write!(f, "{}", self.0) // delegiert an Ulid::to_string()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
use sqlx::{
|
|
||||||
postgres::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueRef},
|
|
||||||
Decode, Encode, Postgres, Type,
|
|
||||||
};
|
|
||||||
|
|
||||||
// #[derive(sqlx::Type)]
|
|
||||||
// #[sqlx(type_name = "ULID")]
|
|
||||||
// #[sqlx(no_pg_array)]
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub struct Ulid(pub ulid::Ulid);
|
|
||||||
|
|
||||||
#[Scalar]
|
#[Scalar]
|
||||||
impl ScalarType for Ulid {
|
impl ScalarType for Ulid {
|
||||||
fn parse(value: Value) -> InputValueResult<Self> {
|
fn parse(value: Value) -> InputValueResult<Self> {
|
||||||
match value {
|
match value {
|
||||||
Value::String(s) => {
|
Value::String(s) => {
|
||||||
let ulid = ulid::Ulid::from_string(&s).map_err(InputValueError::custom)?;
|
let ulid = UlidPrimitive::from_string(&s).map_err(InputValueError::custom)?;
|
||||||
Ok(Ulid(ulid))
|
Ok(Ulid(ulid))
|
||||||
}
|
}
|
||||||
_ => Err(InputValueError::expected_type(value)),
|
_ => Err(InputValueError::expected_type(value)),
|
||||||
@@ -75,17 +34,19 @@ impl ScalarType for Ulid {
|
|||||||
|
|
||||||
impl Type<Postgres> for Ulid {
|
impl Type<Postgres> for Ulid {
|
||||||
fn type_info() -> PgTypeInfo {
|
fn type_info() -> PgTypeInfo {
|
||||||
PgTypeInfo::with_name("ULID")
|
<String as Type<Postgres>>::type_info()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compatible(ty: &PgTypeInfo) -> bool {
|
fn compatible(ty: &PgTypeInfo) -> bool {
|
||||||
<String as Type<Postgres>>::compatible(ty)
|
<String as Type<Postgres>>::compatible(ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'r> Decode<'r, Postgres> for Ulid {
|
impl<'r> Decode<'r, Postgres> for Ulid {
|
||||||
fn decode(value: PgValueRef<'r>) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
fn decode(value: PgValueRef<'r>) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let s = <String as Decode<Postgres>>::decode(value)?;
|
let s = <String as Decode<Postgres>>::decode(value)?;
|
||||||
|
|
||||||
Ok(Ulid(ulid::Ulid::from_string(s.trim())?))
|
Ok(Ulid(UlidPrimitive::from_string(s.trim())?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,8 +58,9 @@ impl<'q> Encode<'q, Postgres> for Ulid {
|
|||||||
<String as Encode<Postgres>>::encode(self.0.to_string(), buf)
|
<String as Encode<Postgres>>::encode(self.0.to_string(), buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PgHasArrayType for Ulid {
|
impl PgHasArrayType for Ulid {
|
||||||
fn array_type_info() -> PgTypeInfo {
|
fn array_type_info() -> PgTypeInfo {
|
||||||
PgTypeInfo::with_name("_ULID")
|
<String as PgHasArrayType>::array_type_info()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user