Die Tabellen Benutzer, Rollen und Gruppen hinzugefügt
This commit is contained in:
@@ -5,5 +5,5 @@ pub struct Rolle {
|
||||
pub id: Id,
|
||||
pub created_at: Time,
|
||||
pub updated_at: Time,
|
||||
pub name: String,
|
||||
pub rollenname: String,
|
||||
}
|
||||
|
||||
@@ -2,5 +2,6 @@ mod rolle;
|
||||
mod rolle_create_input;
|
||||
mod rolle_update_input;
|
||||
|
||||
pub use rolle::Gruppe;
|
||||
pub use rolle::Rolle;
|
||||
pub use rolle_create_input::RolleCreateInput;
|
||||
|
||||
@@ -2,17 +2,35 @@ use async_graphql::SimpleObject;
|
||||
|
||||
use crate::scalar::{Id, Time};
|
||||
|
||||
#[derive(Debug, SimpleObject)]
|
||||
#[derive(Debug, SimpleObject, sqlx::FromRow)]
|
||||
pub struct Rolle {
|
||||
/// Die ID einer Rolle
|
||||
pub id: Id,
|
||||
|
||||
/// Wann die Rolle erstellt wurde
|
||||
/// Zeit wann die Rolle erstellt wurde
|
||||
pub created_at: Time,
|
||||
|
||||
/// Wann die Rolle geändert wurde
|
||||
/// Zeit wann die Rolle geändert wurde
|
||||
pub updated_at: Time,
|
||||
|
||||
/// Der Name einer Rolle
|
||||
pub name: String,
|
||||
pub rollenname: String,
|
||||
|
||||
pub gruppen: Vec<Gruppe>,
|
||||
}
|
||||
|
||||
/// 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,
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@ use async_graphql::InputObject;
|
||||
#[derive(InputObject)]
|
||||
pub struct RolleCreateInput {
|
||||
/// Der Name einer Rolle
|
||||
pub name: String,
|
||||
pub rollenname: String,
|
||||
}
|
||||
|
||||
@@ -8,5 +8,5 @@ pub struct RolleUpdateInput {
|
||||
pub id: Id,
|
||||
|
||||
/// Der Name einer Rolle
|
||||
pub name: String,
|
||||
pub rollenname: String,
|
||||
}
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
use anyhow::Error;
|
||||
|
||||
use super::Repository;
|
||||
// use crate::domain::rolle::model;
|
||||
use crate::{database::Queryer, domain::rolle::entity};
|
||||
use crate::database::Queryer;
|
||||
use crate::domain::rolle::entity;
|
||||
use crate::scalar::Id;
|
||||
|
||||
impl Repository {
|
||||
pub async fn create_rolle<'c, C: Queryer<'c>>(
|
||||
&self,
|
||||
db: C,
|
||||
rolle: &entity::Rolle,
|
||||
) -> Result<entity::Rolle, Error> {
|
||||
) -> Result<Id, Error> {
|
||||
const QUERY: &str = "insert into rolle (id, created_at, updated_at,
|
||||
name) values ($1, $2, $3, $4) returning *";
|
||||
name) values ($1, $2, $3, $4) returning id";
|
||||
|
||||
match sqlx::query_as::<_, entity::Rolle>(QUERY)
|
||||
match sqlx::query_scalar::<_, Id>(QUERY)
|
||||
.bind(rolle.id)
|
||||
.bind(rolle.created_at)
|
||||
.bind(rolle.updated_at)
|
||||
.bind(&rolle.name)
|
||||
.bind(&rolle.rollenname)
|
||||
.fetch_one(db)
|
||||
.await
|
||||
{
|
||||
@@ -25,7 +26,7 @@ impl Repository {
|
||||
tracing::error!("{}", &err);
|
||||
Err(err.into())
|
||||
}
|
||||
Ok(user) => Ok(user),
|
||||
Ok(id) => Ok(id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
use anyhow::Error;
|
||||
|
||||
use super::Repository;
|
||||
use crate::database::Queryer;
|
||||
use crate::domain::rolle::model::{self};
|
||||
use crate::scalar::Id;
|
||||
|
||||
impl Repository {
|
||||
pub async fn find_rolle_by_id<'c, C: Queryer<'c>>(
|
||||
&self,
|
||||
db: C,
|
||||
id: Id,
|
||||
) -> Result<model::Rolle, Error> {
|
||||
const QUERY: &str = r#"
|
||||
select
|
||||
r.id, r.created_at, r.updated_at, r.rollenname,
|
||||
(g.id, g.created_at, g.updated_at, g.gruppenname) as "gruppen!: Vec<model::Gruppe>"
|
||||
from rollen as r
|
||||
join rollen_gruppen as rg on rg.rolle_id = r.id
|
||||
join gruppen as g on rg.gruppe_id = g.id
|
||||
where r.id = $1;
|
||||
"#;
|
||||
|
||||
let row = sqlx::query_as::<_, model::Rolle>(QUERY)
|
||||
.bind(id)
|
||||
.fetch_one(db)
|
||||
.await?;
|
||||
|
||||
// let row = sqlx::query_as!(
|
||||
// model::Rolle,
|
||||
// r#"
|
||||
// select
|
||||
// r.id, r.created_at, r.updated_at, r.rollenname,
|
||||
// (g.id, g.created_at, g.updated_at, g.gruppenname) as "gruppen!: Vec<model::Gruppe>"
|
||||
// from rollen as r
|
||||
// join rollen_gruppen as rg on rg.rolle_id = r.id
|
||||
// join gruppen as g on rg.gruppe_id = g.id
|
||||
// where r.id = $1;
|
||||
// "#,
|
||||
// id
|
||||
// )
|
||||
// .fetch_one(db)
|
||||
// .await?;
|
||||
|
||||
Ok(row)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,11 @@ use chrono::Utc;
|
||||
use ulid::Ulid;
|
||||
|
||||
use super::Service;
|
||||
use crate::domain::rolle::entity;
|
||||
use crate::domain::rolle::model::RolleCreateInput;
|
||||
use crate::domain::rolle::{entity, model};
|
||||
|
||||
impl Service {
|
||||
pub async fn create_rolle(&self, input: RolleCreateInput) -> Result<entity::Rolle, Error> {
|
||||
pub async fn create_rolle(&self, input: RolleCreateInput) -> Result<model::Rolle, Error> {
|
||||
// let username_exists = self.check_username_exists(&self.db, &input.name).await?;
|
||||
// if username_exists {
|
||||
// return Err(Error::UsernameAlreadyExists.into());
|
||||
@@ -15,12 +15,13 @@ impl Service {
|
||||
|
||||
let rolle_input = entity::Rolle {
|
||||
id: Ulid::new().into(),
|
||||
name: input.name,
|
||||
rollenname: input.rollenname,
|
||||
created_at: Utc::now(),
|
||||
updated_at: Utc::now(),
|
||||
};
|
||||
|
||||
let rolle = self.repo.create_rolle(&self.db, &rolle_input).await?;
|
||||
let created_id = self.repo.create_rolle(&self.db, &rolle_input).await?;
|
||||
let rolle = self.repo.find_rolle_by_id(&self.db, created_id).await?;
|
||||
Ok(rolle)
|
||||
}
|
||||
}
|
||||
|
||||
8
src/format.sql
Normal file
8
src/format.sql
Normal file
@@ -0,0 +1,8 @@
|
||||
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;
|
||||
12
src/main.rs
12
src/main.rs
@@ -13,7 +13,7 @@ use dotenv::dotenv;
|
||||
use mutations::Mutation;
|
||||
use queries::Query;
|
||||
use sqlx::postgres::PgPool;
|
||||
use std::env;
|
||||
use std::{env, sync::Arc};
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
mod config;
|
||||
@@ -38,13 +38,17 @@ async fn graphiql() -> impl IntoResponse {
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
// tracing_subscriber::fmt()
|
||||
// .with_max_level(tracing::Level::DEBUG)
|
||||
// .init();
|
||||
|
||||
dotenv().ok();
|
||||
env_logger::init();
|
||||
|
||||
Config::load();
|
||||
// Config::load();
|
||||
let config = Arc::new(Config::load()?);
|
||||
|
||||
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL is not set");
|
||||
let db_pool = PgPool::connect(&database_url).await?;
|
||||
let db_pool = PgPool::connect(&config.database.url).await?;
|
||||
|
||||
let schema = Schema::build(Query::default(), Mutation::default(), EmptySubscription)
|
||||
.data(db_pool)
|
||||
|
||||
78
src/models/benutzer.rs
Normal file
78
src/models/benutzer.rs
Normal file
@@ -0,0 +1,78 @@
|
||||
use async_graphql::{Context, FieldResult, Object};
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::{models::gruppe::Gruppe, scalar::Id};
|
||||
|
||||
use super::rolle::Rolle;
|
||||
|
||||
pub struct Benutzer {
|
||||
pub id: Id,
|
||||
pub kennung: String,
|
||||
pub vorname: String,
|
||||
pub nachname: String,
|
||||
}
|
||||
|
||||
#[Object]
|
||||
impl Benutzer {
|
||||
pub async fn id(&self) -> Id {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub async fn kennung(&self) -> &str {
|
||||
&self.kennung
|
||||
}
|
||||
|
||||
pub async fn vorname(&self) -> &str {
|
||||
&self.vorname
|
||||
}
|
||||
|
||||
pub async fn nachname(&self) -> &str {
|
||||
&self.nachname
|
||||
}
|
||||
|
||||
pub async fn rollen<'ctx>(&self, ctx: &Context<'ctx>) -> FieldResult<Vec<Rolle>> {
|
||||
let pool = ctx.data::<PgPool>()?;
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
pub async fn gruppen<'ctx>(&self, ctx: &Context<'ctx>) -> FieldResult<Vec<Gruppe>> {
|
||||
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 benutzer_gruppen AS bg ON g.id = bg.gruppe_id
|
||||
WHERE bg.benutzer_id = $1;
|
||||
"#,
|
||||
&self.id
|
||||
)
|
||||
.fetch_all(pool)
|
||||
.await?;
|
||||
|
||||
Ok(rows)
|
||||
}
|
||||
}
|
||||
30
src/models/gruppe.rs
Normal file
30
src/models/gruppe.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
use async_graphql::Object;
|
||||
|
||||
use crate::scalar::{Id, Time};
|
||||
|
||||
pub struct Gruppe {
|
||||
pub id: Id,
|
||||
pub gruppenname: String,
|
||||
|
||||
pub erstellt_am: Time,
|
||||
pub geaendert_am: Time,
|
||||
}
|
||||
|
||||
#[Object]
|
||||
impl Gruppe {
|
||||
pub async fn id(&self) -> Id {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub async fn gruppenname(&self) -> &str {
|
||||
&self.gruppenname
|
||||
}
|
||||
|
||||
pub async fn erstellt_am(&self) -> Time {
|
||||
self.erstellt_am
|
||||
}
|
||||
|
||||
pub async fn geaendert_am(&self) -> Time {
|
||||
self.geaendert_am
|
||||
}
|
||||
}
|
||||
@@ -2,33 +2,36 @@ use anyhow::Result;
|
||||
use async_graphql::{InputObject, SimpleObject};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::{FromRow, PgPool};
|
||||
use ulid::Ulid;
|
||||
|
||||
use crate::scalar::Id;
|
||||
|
||||
#[derive(SimpleObject, Debug, FromRow, Deserialize, Serialize, sqlx::Type)]
|
||||
pub struct Hersteller {
|
||||
/// Die Datenbank-ID
|
||||
pub id: i32,
|
||||
pub id: Id,
|
||||
|
||||
/// Der Name eines Herstellers
|
||||
name: String,
|
||||
herstellername: String,
|
||||
}
|
||||
|
||||
#[derive(InputObject, Debug)]
|
||||
pub struct HerstellerCreateInput {
|
||||
/// Der Name eines Herstellers
|
||||
pub name: String,
|
||||
pub herstellername: String,
|
||||
}
|
||||
|
||||
#[derive(InputObject, Debug)]
|
||||
pub struct HerstellerUpdateInput {
|
||||
/// Die Datenbank-ID
|
||||
pub id: i32,
|
||||
pub id: Id,
|
||||
|
||||
/// Der Name eines Herstellers
|
||||
pub name: Option<String>,
|
||||
pub herstellername: Option<String>,
|
||||
}
|
||||
|
||||
impl Hersteller {
|
||||
pub async fn read_one(pool: &PgPool, id: &i32) -> Result<Hersteller> {
|
||||
pub async fn read_one(pool: &PgPool, id: &Id) -> Result<Hersteller> {
|
||||
let row = sqlx::query_as!(Hersteller, "SELECT * FROM hersteller WHERE id = $1", id)
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
@@ -37,7 +40,7 @@ impl Hersteller {
|
||||
}
|
||||
|
||||
pub async fn read_all(pool: &PgPool) -> Result<Vec<Hersteller>> {
|
||||
let rows = sqlx::query_as!(Hersteller, "SELECT id, name FROM hersteller")
|
||||
let rows = sqlx::query_as!(Hersteller, "SELECT id, herstellername FROM hersteller")
|
||||
.fetch_all(pool)
|
||||
.await?;
|
||||
|
||||
@@ -45,21 +48,21 @@ impl Hersteller {
|
||||
}
|
||||
|
||||
pub async fn create(pool: &PgPool, input: &HerstellerCreateInput) -> Result<Hersteller> {
|
||||
let row = sqlx::query!(
|
||||
"INSERT INTO hersteller(name) VALUES ($1) RETURNING id",
|
||||
input.name
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
const QUERY: &str = "INSERT INTO hersteller (id, herstellername) VALUES ($1, $2) RETURNING id, herstellername";
|
||||
|
||||
let result: Hersteller = sqlx::query_as::<_, Hersteller>(QUERY)
|
||||
.bind::<Id>(Ulid::new().into())
|
||||
.bind(&input.herstellername)
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
|
||||
let result = Self::read_one(pool, &row.id).await?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn update(pool: &PgPool, input: &HerstellerUpdateInput) -> Result<Hersteller> {
|
||||
sqlx::query!(
|
||||
"UPDATE hersteller SET name=$1 WHERE id = $2",
|
||||
input.name,
|
||||
"UPDATE hersteller SET herstellername=$1 WHERE id = $2",
|
||||
input.herstellername,
|
||||
input.id
|
||||
)
|
||||
.execute(pool)
|
||||
@@ -70,7 +73,7 @@ impl Hersteller {
|
||||
Ok(t)
|
||||
}
|
||||
|
||||
pub async fn delete(pool: &PgPool, id: &i32) -> Result<bool> {
|
||||
pub async fn delete(pool: &PgPool, id: &Id) -> Result<bool> {
|
||||
let result = sqlx::query!("DELETE FROM hersteller WHERE id = $1", id)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
pub mod benutzer;
|
||||
pub mod gruppe;
|
||||
pub mod hersteller;
|
||||
pub mod modell;
|
||||
pub mod rolle;
|
||||
pub mod typ;
|
||||
|
||||
@@ -2,13 +2,17 @@ use anyhow::Result;
|
||||
use async_graphql::{InputObject, SimpleObject};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::{FromRow, PgPool};
|
||||
use ulid::Ulid;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::scalar::Id;
|
||||
|
||||
use super::{hersteller::Hersteller, typ::Typ};
|
||||
|
||||
#[derive(SimpleObject, FromRow, Deserialize, Serialize, Debug)]
|
||||
pub struct Modell {
|
||||
/// Die Datenbank-ID
|
||||
pub id: i32,
|
||||
pub id: Id,
|
||||
|
||||
/// Der Geräte-Typ z.B. Monitor
|
||||
typ: Typ,
|
||||
@@ -17,38 +21,44 @@ pub struct Modell {
|
||||
hersteller: Hersteller,
|
||||
|
||||
/// Der Name eines Modells
|
||||
name: String,
|
||||
modellname: String,
|
||||
}
|
||||
|
||||
#[derive(InputObject, Debug)]
|
||||
pub struct ModellCreateInput {
|
||||
pub name: String,
|
||||
pub typ_id: i32,
|
||||
pub hersteller_id: i32,
|
||||
/// Der Name eines Modells
|
||||
pub modellname: String,
|
||||
|
||||
/// Die Id eines Geräte-Typs z.B. Monitor
|
||||
pub typ_id: Id,
|
||||
|
||||
/// Die Id eines Geräte-Herstellers z.B. Dell
|
||||
pub hersteller_id: Id,
|
||||
}
|
||||
|
||||
#[derive(InputObject, Debug)]
|
||||
pub struct ModellUpdateInput {
|
||||
pub id: i32,
|
||||
pub name: Option<String>,
|
||||
pub typ_id: Option<i32>,
|
||||
pub hersteller_id: Option<i32>,
|
||||
pub id: Id,
|
||||
pub modellname: Option<String>,
|
||||
pub typ_id: Option<Id>,
|
||||
pub hersteller_id: Option<Id>,
|
||||
}
|
||||
|
||||
impl Modell {
|
||||
pub async fn read_one(pool: &PgPool, id: &i32) -> Result<Modell> {
|
||||
pub async fn read_one(pool: &PgPool, id: &Id) -> Result<Modell> {
|
||||
let row = sqlx::query_as!(
|
||||
Modell,
|
||||
r#"
|
||||
select
|
||||
m.id, m.name,
|
||||
(t.id, t.name) as "typ!: Typ",
|
||||
(h.id, h.name) as "hersteller!: Hersteller"
|
||||
from modelle as m
|
||||
join typen as t on t.id = m.typ_id
|
||||
join hersteller as h on h.id = m.hersteller_id
|
||||
where m.id = $1;
|
||||
"#,
|
||||
SELECT
|
||||
m.id,
|
||||
m.modellname,
|
||||
(t.id, t.typname) AS "typ!: Typ",
|
||||
(h.id, h.herstellername) AS "hersteller!: Hersteller"
|
||||
FROM modelle AS m
|
||||
JOIN typen AS t ON t.id = m.typ_id
|
||||
JOIN hersteller AS h ON h.id = m.hersteller_id
|
||||
WHERE m.id = $1;
|
||||
"#,
|
||||
id
|
||||
)
|
||||
.fetch_one(pool)
|
||||
@@ -61,14 +71,15 @@ impl Modell {
|
||||
let row = sqlx::query_as!(
|
||||
Modell,
|
||||
r#"
|
||||
select
|
||||
m.id, m.name,
|
||||
(t.id, t.name) as "typ!: Typ",
|
||||
(h.id, h.name) as "hersteller!: Hersteller"
|
||||
from modelle as m
|
||||
join typen as t on t.id = m.typ_id
|
||||
join hersteller as h on h.id = m.hersteller_id
|
||||
"#
|
||||
SELECT
|
||||
m.id,
|
||||
m.modellname,
|
||||
(t.id, t.typname) AS "typ!: Typ",
|
||||
(h.id, h.herstellername) AS "hersteller!: Hersteller"
|
||||
FROM modelle AS m
|
||||
LEFT JOIN typen AS t ON t.id = m.typ_id
|
||||
LEFT JOIN hersteller AS h ON h.id = m.hersteller_id
|
||||
"#
|
||||
)
|
||||
.fetch_all(pool)
|
||||
.await?;
|
||||
@@ -77,22 +88,25 @@ impl Modell {
|
||||
}
|
||||
|
||||
pub async fn create(pool: &PgPool, input: &ModellCreateInput) -> Result<Modell> {
|
||||
let row = sqlx::query!(
|
||||
r#"INSERT INTO modelle(typ_id, hersteller_id, name) VALUES ($1, $2, $3) RETURNING id"#,
|
||||
input.typ_id,
|
||||
input.hersteller_id,
|
||||
input.name
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
const QUERY: &str = "INSERT INTO modelle (id, typ_id, hersteller_id, modellname) VALUES ($1, $2, $3, $4) RETURNING id";
|
||||
|
||||
Self::read_one(pool, &row.id).await
|
||||
let row: (Uuid,) = sqlx::query_as(QUERY)
|
||||
.bind::<Id>(Ulid::new().into())
|
||||
.bind(input.typ_id)
|
||||
.bind(input.hersteller_id)
|
||||
.bind(&input.modellname)
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
|
||||
let modell = Modell::read_one(pool, &row.0).await?;
|
||||
|
||||
Ok(modell)
|
||||
}
|
||||
|
||||
pub async fn update(pool: &PgPool, input: &ModellUpdateInput) -> Result<Modell> {
|
||||
sqlx::query!(
|
||||
"UPDATE modelle SET name=COALESCE($1, name), typ_id=COALESCE($2, typ_id), hersteller_id=COALESCE($3, hersteller_id) WHERE id = $4",
|
||||
input.name,
|
||||
"UPDATE modelle SET modellname=COALESCE($1, modellname), typ_id=COALESCE($2, typ_id), hersteller_id=COALESCE($3, hersteller_id) WHERE id = $4",
|
||||
input.modellname,
|
||||
input.typ_id,
|
||||
input.hersteller_id,
|
||||
input.id
|
||||
@@ -105,7 +119,7 @@ impl Modell {
|
||||
Ok(t)
|
||||
}
|
||||
|
||||
pub async fn delete(pool: &PgPool, id: &i32) -> Result<bool> {
|
||||
pub async fn delete(pool: &PgPool, id: &Id) -> Result<bool> {
|
||||
let result = sqlx::query!("DELETE FROM modelle WHERE id = $1", id)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
57
src/models/rolle.rs
Normal file
57
src/models/rolle.rs
Normal file
@@ -0,0 +1,57 @@
|
||||
use async_graphql::{Context, FieldResult, Object};
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::scalar::{Id, Time};
|
||||
|
||||
use super::gruppe::Gruppe;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Rolle {
|
||||
pub id: Id,
|
||||
pub rollenname: String,
|
||||
|
||||
pub erstellt_am: Time,
|
||||
pub geaendert_am: Time,
|
||||
}
|
||||
|
||||
#[Object]
|
||||
impl Rolle {
|
||||
pub async fn id(&self) -> Id {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub async fn rollename(&self) -> &str {
|
||||
&self.rollenname
|
||||
}
|
||||
|
||||
pub async fn erstellt_am(&self) -> Time {
|
||||
self.erstellt_am
|
||||
}
|
||||
|
||||
pub async fn geaendert_am(&self) -> Time {
|
||||
self.geaendert_am
|
||||
}
|
||||
|
||||
pub async fn gruppen<'ctx>(&self, ctx: &Context<'ctx>) -> FieldResult<Vec<Gruppe>> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -2,29 +2,32 @@ use anyhow::Result;
|
||||
use async_graphql::{InputObject, SimpleObject};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::{FromRow, PgPool, Type};
|
||||
use ulid::Ulid;
|
||||
|
||||
use crate::scalar::Id;
|
||||
|
||||
#[derive(SimpleObject, Debug, FromRow, Deserialize, Serialize, Type)]
|
||||
pub struct Typ {
|
||||
/// Die ID eines Geräte-Typs
|
||||
pub id: i32,
|
||||
pub id: Id,
|
||||
|
||||
/// Der Name eines Geräte-Typs
|
||||
pub name: String,
|
||||
pub typname: String,
|
||||
}
|
||||
|
||||
#[derive(InputObject, Debug)]
|
||||
pub struct TypCreateInput {
|
||||
pub name: String,
|
||||
pub typname: String,
|
||||
}
|
||||
|
||||
#[derive(InputObject, Debug)]
|
||||
pub struct TypUpdateInput {
|
||||
pub id: i32,
|
||||
pub name: Option<String>,
|
||||
pub id: Id,
|
||||
pub typname: Option<String>,
|
||||
}
|
||||
|
||||
impl Typ {
|
||||
pub async fn read_one(pool: &PgPool, id: &i32) -> Result<Typ> {
|
||||
pub async fn read_one(pool: &PgPool, id: &Id) -> Result<Typ> {
|
||||
const QUERY: &str = "SELECT * FROM typen WHERE id = $1";
|
||||
let row: Typ = sqlx::query_as(QUERY).bind(id).fetch_one(pool).await?;
|
||||
|
||||
@@ -32,7 +35,7 @@ impl Typ {
|
||||
}
|
||||
|
||||
pub async fn read_all(pool: &PgPool) -> Result<Vec<Typ>> {
|
||||
let rows = sqlx::query_as!(Typ, "SELECT id, name FROM typen")
|
||||
let rows = sqlx::query_as!(Typ, "SELECT id, typname FROM typen")
|
||||
.fetch_all(pool)
|
||||
.await?;
|
||||
|
||||
@@ -40,10 +43,11 @@ impl Typ {
|
||||
}
|
||||
|
||||
pub async fn create(pool: &PgPool, input: &TypCreateInput) -> Result<Typ> {
|
||||
const QUERY: &str = "INSERT INTO typen (name) VALUES ($1) RETURNING id, name";
|
||||
const QUERY: &str = "INSERT INTO typen (id, typname) VALUES ($1, $2) RETURNING id, typname";
|
||||
|
||||
let result: Typ = sqlx::query_as(QUERY)
|
||||
.bind(&input.name)
|
||||
let result: Typ = sqlx::query_as::<_, Typ>(QUERY)
|
||||
.bind::<Id>(Ulid::new().into())
|
||||
.bind(&input.typname)
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
|
||||
@@ -52,14 +56,14 @@ impl Typ {
|
||||
|
||||
pub async fn create_many(pool: &PgPool, input: &[TypCreateInput]) -> Result<Vec<Typ>> {
|
||||
let mut v1: Vec<&str> = Vec::new();
|
||||
input.iter().for_each(|typ| v1.push(&typ.name));
|
||||
input.iter().for_each(|typ| v1.push(&typ.typname));
|
||||
|
||||
let row = sqlx::query_as!(
|
||||
Typ,
|
||||
r#"
|
||||
INSERT INTO typen(name)
|
||||
INSERT INTO typen(typname)
|
||||
SELECT * FROM UNNEST($1::text[])
|
||||
RETURNING id, name"#,
|
||||
RETURNING id, typname"#,
|
||||
&v1 as _
|
||||
)
|
||||
.fetch_all(pool)
|
||||
@@ -70,8 +74,8 @@ impl Typ {
|
||||
|
||||
pub async fn update(pool: &PgPool, input: &TypUpdateInput) -> Result<Typ> {
|
||||
sqlx::query!(
|
||||
"UPDATE typen SET name=$1 WHERE id = $2",
|
||||
input.name,
|
||||
"UPDATE typen SET typname=$1 WHERE id = $2",
|
||||
input.typname,
|
||||
input.id
|
||||
)
|
||||
.execute(pool)
|
||||
@@ -81,7 +85,7 @@ impl Typ {
|
||||
Ok(t)
|
||||
}
|
||||
|
||||
pub async fn delete(pool: &PgPool, id: &i32) -> Result<bool> {
|
||||
pub async fn delete(pool: &PgPool, id: &Id) -> Result<bool> {
|
||||
let result = sqlx::query!("DELETE FROM typen WHERE id = $1", id)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use crate::models::hersteller::{Hersteller, HerstellerCreateInput, HerstellerUpdateInput};
|
||||
use crate::{
|
||||
models::hersteller::{Hersteller, HerstellerCreateInput, HerstellerUpdateInput},
|
||||
scalar::Id,
|
||||
};
|
||||
use async_graphql::{Context, FieldResult};
|
||||
use sqlx::postgres::PgPool;
|
||||
|
||||
@@ -27,7 +30,7 @@ impl HerstellerMutation {
|
||||
Ok(row)
|
||||
}
|
||||
|
||||
async fn delete_hersteller(&self, ctx: &Context<'_>, id: i32) -> FieldResult<bool> {
|
||||
async fn delete_hersteller(&self, ctx: &Context<'_>, id: Id) -> FieldResult<bool> {
|
||||
let pool = ctx.data::<PgPool>()?;
|
||||
Ok(Hersteller::delete(pool, &id).await?)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::models::modell::*;
|
||||
use crate::{models::modell::*, scalar::Id};
|
||||
use async_graphql::{Context, FieldResult};
|
||||
use sqlx::postgres::PgPool;
|
||||
|
||||
@@ -26,7 +26,7 @@ impl ModellMutation {
|
||||
let row = Modell::update(pool, &input).await?;
|
||||
Ok(row)
|
||||
}
|
||||
async fn delete_modell(&self, ctx: &Context<'_>, id: i32) -> FieldResult<bool> {
|
||||
async fn delete_modell(&self, ctx: &Context<'_>, id: Id) -> FieldResult<bool> {
|
||||
let pool = ctx.data::<PgPool>()?;
|
||||
Ok(Modell::delete(pool, &id).await?)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use crate::models::typ::{Typ, TypCreateInput, TypUpdateInput};
|
||||
use crate::{
|
||||
models::typ::{Typ, TypCreateInput, TypUpdateInput},
|
||||
scalar::Id,
|
||||
};
|
||||
use async_graphql::{Context, FieldResult};
|
||||
use sqlx::postgres::PgPool;
|
||||
|
||||
@@ -9,6 +12,7 @@ pub struct TypMutation;
|
||||
impl TypMutation {
|
||||
async fn create_typ(&self, ctx: &Context<'_>, input: TypCreateInput) -> FieldResult<Typ> {
|
||||
let pool = ctx.data::<PgPool>()?;
|
||||
|
||||
let row = Typ::create(pool, &input).await?;
|
||||
Ok(row)
|
||||
}
|
||||
@@ -29,7 +33,7 @@ impl TypMutation {
|
||||
Ok(row)
|
||||
}
|
||||
|
||||
async fn delete_typ(&self, ctx: &Context<'_>, id: i32) -> FieldResult<bool> {
|
||||
async fn delete_typ(&self, ctx: &Context<'_>, id: Id) -> FieldResult<bool> {
|
||||
let pool = ctx.data::<PgPool>()?;
|
||||
Ok(Typ::delete(pool, &id).await?)
|
||||
}
|
||||
|
||||
26
src/queries/benutzer.rs
Normal file
26
src/queries/benutzer.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use async_graphql::{Context, FieldResult, Object};
|
||||
use sqlx::postgres::PgPool;
|
||||
|
||||
use crate::models::benutzer::Benutzer;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BenutzerQuery {}
|
||||
|
||||
#[Object(extends)]
|
||||
impl BenutzerQuery {
|
||||
// async fn rolle<'a>(&self, ctx: &'a Context<'_>, id: Id) -> FieldResult<Modell> {
|
||||
// let pool = ctx.data::<PgPool>()?;
|
||||
// let row = Modell::read_one(pool, &id).await?;
|
||||
// Ok(row)
|
||||
// }
|
||||
|
||||
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?;
|
||||
|
||||
Ok(benutzer)
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,11 @@ pub struct HerstellerQuery {}
|
||||
|
||||
#[Object(extends)]
|
||||
impl HerstellerQuery {
|
||||
async fn hersteller<'a>(&self, ctx: &'a Context<'_>, id: i32) -> FieldResult<Hersteller> {
|
||||
async fn hersteller<'a>(
|
||||
&self,
|
||||
ctx: &'a Context<'_>,
|
||||
id: uuid::Uuid,
|
||||
) -> FieldResult<Hersteller> {
|
||||
let pool = ctx.data::<PgPool>()?;
|
||||
let row = Hersteller::read_one(pool, &id).await?;
|
||||
Ok(row)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
pub mod benutzer;
|
||||
pub mod hersteller;
|
||||
pub mod modell;
|
||||
pub mod rolle;
|
||||
pub mod typ;
|
||||
|
||||
use async_graphql::MergedObject;
|
||||
@@ -9,4 +11,6 @@ pub struct Query(
|
||||
typ::TypQuery,
|
||||
modell::ModellQuery,
|
||||
hersteller::HerstellerQuery,
|
||||
benutzer::BenutzerQuery,
|
||||
rolle::RolleQuery,
|
||||
);
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use async_graphql::{Context, FieldResult, Object};
|
||||
use sqlx::postgres::PgPool;
|
||||
|
||||
use crate::models::modell::Modell;
|
||||
use crate::{models::modell::Modell, scalar::Id};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ModellQuery {}
|
||||
|
||||
#[Object(extends)]
|
||||
impl ModellQuery {
|
||||
async fn modell<'a>(&self, ctx: &'a Context<'_>, id: i32) -> FieldResult<Modell> {
|
||||
async fn modell<'a>(&self, ctx: &'a Context<'_>, id: Id) -> FieldResult<Modell> {
|
||||
let pool = ctx.data::<PgPool>()?;
|
||||
let row = Modell::read_one(pool, &id).await?;
|
||||
Ok(row)
|
||||
|
||||
27
src/queries/rolle.rs
Normal file
27
src/queries/rolle.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
use async_graphql::{Context, FieldResult, Object};
|
||||
use log::debug;
|
||||
use sqlx::postgres::PgPool;
|
||||
|
||||
use crate::models::rolle::Rolle;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RolleQuery {}
|
||||
|
||||
#[Object(extends)]
|
||||
impl RolleQuery {
|
||||
// async fn rolle<'a>(&self, ctx: &'a Context<'_>, id: Id) -> FieldResult<Modell> {
|
||||
// let pool = ctx.data::<PgPool>()?;
|
||||
// let row = Modell::read_one(pool, &id).await?;
|
||||
// Ok(row)
|
||||
// }
|
||||
|
||||
async fn rollen<'a>(&self, ctx: &'a Context<'_>) -> FieldResult<Vec<Rolle>> {
|
||||
let pool = ctx.data::<PgPool>()?;
|
||||
|
||||
let rollen = sqlx::query_as!(Rolle, "SELECT * FROM rollen")
|
||||
.fetch_all(pool)
|
||||
.await?;
|
||||
|
||||
Ok(rollen)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
use async_graphql::{Context, FieldResult, Object};
|
||||
use sqlx::postgres::PgPool;
|
||||
|
||||
use crate::models::typ::Typ;
|
||||
use crate::{models::typ::Typ, scalar::Id};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct TypQuery {}
|
||||
@@ -14,7 +14,7 @@ impl TypQuery {
|
||||
Ok(rows)
|
||||
}
|
||||
|
||||
async fn typ<'a>(&self, ctx: &'a Context<'_>, id: i32) -> FieldResult<Typ> {
|
||||
async fn typ<'a>(&self, ctx: &'a Context<'_>, id: Id) -> FieldResult<Typ> {
|
||||
let pool = ctx.data::<PgPool>()?;
|
||||
let row = Typ::read_one(pool, &id).await?;
|
||||
Ok(row)
|
||||
|
||||
11
src/tree-sitter.lua
Normal file
11
src/tree-sitter.lua
Normal file
@@ -0,0 +1,11 @@
|
||||
(macro_invocation
|
||||
(scoped_identifier
|
||||
path: (identifier) @path (#eq? @path "sqlx")
|
||||
name: (identifier) @name (#any-of? @name "query_as" "query"))
|
||||
(token_tree [
|
||||
(raw_string_literal) @sql
|
||||
(string_literal) @sql
|
||||
]
|
||||
)
|
||||
(#offset! @sql 1 0 -1 0)
|
||||
)
|
||||
Reference in New Issue
Block a user