First Commit

This commit is contained in:
Peter Schiwy
2024-05-31 00:32:51 +02:00
commit bab592edf1
23 changed files with 3268 additions and 0 deletions

55
src/main.rs Normal file
View File

@@ -0,0 +1,55 @@
extern crate log;
use anyhow::Result;
use async_graphql::{http::GraphiQLSource, EmptySubscription, Schema};
use async_graphql_axum::GraphQL;
use axum::{
response::{self, IntoResponse},
routing::get,
Router,
};
use dotenv::dotenv;
use mutations::Mutation;
use queries::Query;
use sqlx::postgres::PgPool;
use std::env;
use tokio::net::TcpListener;
mod models;
mod mutations;
mod queries;
async fn ping() -> String {
format!(
"I am healthy: {} v{}",
env!("CARGO_PKG_DESCRIPTION"),
env!("CARGO_PKG_VERSION")
)
}
async fn graphiql() -> impl IntoResponse {
response::Html(GraphiQLSource::build().endpoint("/").finish())
}
#[tokio::main]
async fn main() -> Result<()> {
dotenv().ok();
env_logger::init();
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL is not set");
let db_pool = PgPool::connect(&database_url).await?;
let schema = Schema::build(Query::default(), Mutation::default(), EmptySubscription)
.data(db_pool)
.finish();
let app = Router::new()
.route("/ping", get(ping))
.route("/", get(graphiql).post_service(GraphQL::new(schema)));
println!("GraphiQL IDE: http://localhost:8000");
axum::serve(TcpListener::bind("127.0.0.1:8000").await?, app).await?;
Ok(())
}

63
src/models/hersteller.rs Normal file
View File

@@ -0,0 +1,63 @@
use anyhow::Result;
use async_graphql::SimpleObject;
use serde::{Deserialize, Serialize};
use sqlx::{FromRow, PgPool};
#[derive(SimpleObject, FromRow, Deserialize, Serialize)]
pub struct Hersteller {
/// Die Datenbank-ID
pub id: i32,
/// Der Name eines Herstellers
name: String,
}
impl Hersteller {
pub async fn create(pool: &PgPool, name: &str) -> Result<Hersteller> {
let row = sqlx::query!(
"INSERT INTO hersteller(name) VALUES ($1) RETURNING id",
name
)
.fetch_one(pool)
.await?;
Ok(Hersteller {
id: row.id,
name: name.to_string(),
})
}
pub async fn read_one(pool: &PgPool, id: &i32) -> Result<Hersteller> {
let row = sqlx::query_as!(Hersteller, "SELECT * FROM hersteller WHERE id = $1", id)
.fetch_one(pool)
.await?;
Ok(row)
}
pub async fn read_all(pool: &PgPool) -> Result<Vec<Hersteller>> {
let rows = sqlx::query_as!(Hersteller, "SELECT id, name FROM hersteller")
.fetch_all(pool)
.await?;
Ok(rows)
}
pub async fn update(pool: &PgPool, id: &i32, name: &str) -> Result<Hersteller> {
sqlx::query!("UPDATE hersteller SET name=$1 WHERE id = $2", name, id)
.execute(pool)
.await?;
let t = Hersteller::read_one(pool, id).await?;
Ok(t)
}
pub async fn delete(pool: &PgPool, id: &i32) -> Result<()> {
sqlx::query!("DELETE FROM hersteller WHERE id = $1", id)
.execute(pool)
.await?;
Ok(())
}
}

3
src/models/mod.rs Normal file
View File

@@ -0,0 +1,3 @@
pub mod hersteller;
pub mod modell;
pub mod typ;

104
src/models/modell.rs Normal file
View File

@@ -0,0 +1,104 @@
use anyhow::Result;
use async_graphql::SimpleObject;
use serde::{Deserialize, Serialize};
use sqlx::{FromRow, PgPool};
#[derive(SimpleObject, FromRow, Deserialize, Serialize)]
pub struct Modell {
/// Die Datenbank-ID
pub id: i32,
/// Der Typ
typ_id: i32,
/// Der Hersteller
hersteller_id: i32,
/**
* Der Name eines Modells
* Das ist ein Zusatz
*/
name: String,
}
impl Modell {
pub async fn create(
pool: &PgPool,
typ_id: i32,
hersteller_id: i32,
name: &str,
) -> Result<Modell> {
let row = sqlx::query!(
"INSERT INTO modelle(typ_id, hersteller_id, name) VALUES ($1, $2, $3) RETURNING id",
typ_id,
hersteller_id,
name
)
.fetch_one(pool)
.await?;
Ok(Modell {
id: row.id,
typ_id,
hersteller_id,
name: name.to_string(),
})
}
pub async fn read_one(pool: &PgPool, id: &i32) -> Result<Modell> {
let row = sqlx::query_as!(Modell, "SELECT * FROM modelle WHERE id = $1", id)
.fetch_one(pool)
.await?;
Ok(row)
}
pub async fn read_all(pool: &PgPool) -> Result<Vec<Modell>> {
let rows = sqlx::query_as!(
Modell,
"SELECT id, name, hersteller_id, typ_id FROM modelle"
)
.fetch_all(pool)
.await?;
Ok(rows)
}
pub async fn read_by_typ(pool: &PgPool, typ_id: &i32) -> Result<Vec<Modell>> {
let row = sqlx::query_as!(Modell, "SELECT * FROM modelle WHERE typ_id = $1", typ_id)
.fetch_all(pool)
.await?;
Ok(row)
}
pub async fn read_by_hersteller(pool: &PgPool, hersteller_id: &i32) -> Result<Vec<Modell>> {
let row = sqlx::query_as!(
Modell,
"SELECT * FROM modelle WHERE hersteller_id = $1",
hersteller_id
)
.fetch_all(pool)
.await?;
Ok(row)
}
pub async fn update(pool: &PgPool, id: &i32, name: &str) -> Result<Modell> {
sqlx::query!("UPDATE modelle SET name=$1 WHERE id = $2", name, id)
.execute(pool)
.await?;
let t = Modell::read_one(pool, id).await?;
Ok(t)
}
pub async fn delete(pool: &PgPool, id: &i32) -> Result<()> {
sqlx::query!("DELETE FROM modelle WHERE id = $1", id)
.execute(pool)
.await?;
Ok(())
}
}

60
src/models/typ.rs Normal file
View File

@@ -0,0 +1,60 @@
use anyhow::Result;
use async_graphql::SimpleObject;
use serde::{Deserialize, Serialize};
use sqlx::{FromRow, PgPool};
#[derive(SimpleObject, FromRow, Deserialize, Serialize)]
pub struct Typ {
/// Die Datenbank-ID
pub id: i32,
/// Der Name eines Typs
name: String,
}
impl Typ {
pub async fn create(pool: &PgPool, name: &str) -> Result<Typ> {
let row = sqlx::query!("INSERT INTO typen(name) VALUES ($1) RETURNING id", name)
.fetch_one(pool)
.await?;
Ok(Typ {
id: row.id,
name: name.to_string(),
})
}
pub async fn read_one(pool: &PgPool, id: &i32) -> Result<Typ> {
let row = sqlx::query_as!(Typ, "SELECT * FROM typen WHERE id = $1", id)
.fetch_one(pool)
.await?;
Ok(row)
}
pub async fn read_all(pool: &PgPool) -> Result<Vec<Typ>> {
let rows = sqlx::query_as!(Typ, "SELECT id, name FROM typen")
.fetch_all(pool)
.await?;
Ok(rows)
}
pub async fn update(pool: &PgPool, id: &i32, name: &str) -> Result<Typ> {
sqlx::query!("UPDATE typen SET name=$1 WHERE id = $2", name, id)
.execute(pool)
.await?;
let t = Typ::read_one(pool, id).await?;
Ok(t)
}
pub async fn delete(pool: &PgPool, id: &i32) -> Result<()> {
sqlx::query!("DELETE FROM typen WHERE id = $1", id)
.execute(pool)
.await?;
Ok(())
}
}

View File

@@ -0,0 +1,34 @@
use crate::models::hersteller::Hersteller;
use async_graphql::{Context, FieldResult};
use sqlx::postgres::PgPool;
#[derive(Default)]
pub struct HerstellerMutation;
#[async_graphql::Object]
impl HerstellerMutation {
async fn create_hersteller(&self, ctx: &Context<'_>, name: String) -> FieldResult<Hersteller> {
let pool = ctx.data::<PgPool>()?;
let row = Hersteller::create(pool, &name).await?;
Ok(row)
}
async fn delete_hersteller(&self, ctx: &Context<'_>, id: i32) -> FieldResult<bool> {
let pool = ctx.data::<PgPool>()?;
Hersteller::delete(pool, &id).await?;
Ok(true)
}
async fn update_hersteller(
&self,
ctx: &Context<'_>,
id: i32,
name: String,
) -> FieldResult<Hersteller> {
let pool = ctx.data::<PgPool>()?;
let row = Hersteller::update(pool, &id, &name).await?;
Ok(row)
}
}

7
src/mutations/mod.rs Normal file
View File

@@ -0,0 +1,7 @@
pub mod hersteller;
pub mod typ;
use async_graphql::MergedObject;
#[derive(MergedObject, Default)]
pub struct Mutation(typ::TypMutation, hersteller::HerstellerMutation);

29
src/mutations/typ.rs Normal file
View File

@@ -0,0 +1,29 @@
use crate::models::typ::Typ;
use async_graphql::{Context, FieldResult};
use sqlx::postgres::PgPool;
#[derive(Default)]
pub struct TypMutation;
#[async_graphql::Object]
impl TypMutation {
async fn create_typ(&self, ctx: &Context<'_>, name: String) -> FieldResult<Typ> {
let pool = ctx.data::<PgPool>()?;
let row = Typ::create(pool, &name).await?;
Ok(row)
}
async fn delete_typ(&self, ctx: &Context<'_>, id: i32) -> FieldResult<bool> {
let pool = ctx.data::<PgPool>()?;
Typ::delete(pool, &id).await?;
Ok(true)
}
async fn update_typ(&self, ctx: &Context<'_>, id: i32, name: String) -> FieldResult<Typ> {
let pool = ctx.data::<PgPool>()?;
let row = Typ::update(pool, &id, &name).await?;
Ok(row)
}
}

35
src/queries/hersteller.rs Normal file
View File

@@ -0,0 +1,35 @@
use async_graphql::{Context, FieldResult, Object};
use sqlx::postgres::PgPool;
use crate::models::hersteller::Hersteller;
#[derive(Default)]
pub struct HerstellerQuery {
pub id: i32,
}
#[Object(extends)]
impl HerstellerQuery {
// #[graphql(external)]
// async fn id(&self) -> &i32 {
// &self.id
// }
// async fn modell<'a>(&self, ctx: &'a Context<'_>) -> FieldResult<Vec<Modell>> {
// let pool = ctx.data::<PgPool>().unwrap();
// let rows = Modell::read_by_typ(pool, &self.id).await?;
// Ok(rows)
// }
async fn alle_hersteller<'a>(&self, ctx: &'a Context<'_>) -> FieldResult<Vec<Hersteller>> {
let pool = ctx.data::<PgPool>()?;
let rows = Hersteller::read_all(pool).await?;
Ok(rows)
}
async fn hersteller<'a>(&self, ctx: &'a Context<'_>, id: i32) -> FieldResult<Hersteller> {
let pool = ctx.data::<PgPool>()?;
let row = Hersteller::read_one(pool, &id).await?;
Ok(row)
}
}

12
src/queries/mod.rs Normal file
View File

@@ -0,0 +1,12 @@
pub mod hersteller;
pub mod modell;
pub mod typ;
use async_graphql::MergedObject;
#[derive(MergedObject, Default)]
pub struct Query(
typ::TypQuery,
modell::ModellQuery,
hersteller::HerstellerQuery,
);

34
src/queries/modell.rs Normal file
View File

@@ -0,0 +1,34 @@
use async_graphql::{Context, FieldResult, Object};
use sqlx::postgres::PgPool;
use crate::models::modell::Modell;
#[derive(Default)]
pub struct ModellQuery {
pub id: i32,
}
#[Object(extends)]
impl ModellQuery {
// #[graphql(external)]
// async fn id(&self) -> &i32 {
// &self.id
// }
async fn modelle<'a>(&self, ctx: &'a Context<'_>) -> FieldResult<Vec<Modell>> {
let pool = ctx.data::<PgPool>()?;
let rows = Modell::read_all(pool).await?;
Ok(rows)
}
async fn modell<'a>(&self, ctx: &'a Context<'_>, id: i32) -> FieldResult<Modell> {
let pool = ctx.data::<PgPool>()?;
let row = Modell::read_one(pool, &id).await?;
Ok(row)
}
// #[graphql(entity)]
// async fn find_modell_by_id(&self, id: i32) -> Modell {
// Modell { id }
// }
}

41
src/queries/typ.rs Normal file
View File

@@ -0,0 +1,41 @@
use async_graphql::{Context, FieldResult, Object};
use sqlx::postgres::PgPool;
use crate::models::typ::Typ;
#[derive(Default)]
pub struct TypQuery {
pub id: i32,
}
#[Object(extends)]
impl TypQuery {
// #[graphql(external)]
// async fn id(&self) -> &i32 {
// &self.id
// }
// async fn modell<'a>(&self, ctx: &'a Context<'_>) -> FieldResult<Vec<Modell>> {
// let pool = ctx.data::<PgPool>().unwrap();
// let rows = Modell::read_by_typ(pool, &self.id).await?;
// Ok(rows)
// }
async fn typen<'a>(&self, ctx: &'a Context<'_>) -> FieldResult<Vec<Typ>> {
let pool = ctx.data::<PgPool>()?;
let rows = Typ::read_all(pool).await?;
Ok(rows)
}
async fn typ<'a>(&self, ctx: &'a Context<'_>, id: i32) -> FieldResult<Typ> {
let pool = ctx.data::<PgPool>()?;
let row = Typ::read_one(pool, &id).await?;
Ok(row)
}
// #[graphql(entity)]
// async fn find_typ_by_id<'a>(&self, ctx: &'a Context<'_>, id: i32) -> FieldResult<Typ> {
// let pool = ctx.data::<PgPool>().unwrap();
// let row = Typ::read_one(pool, &id).await?;
// Ok(row)
// }
}