From 1d4cda7c48aa6e4cd32b8c7c3fe7c9570b5d4b5a Mon Sep 17 00:00:00 2001 From: kjuulh Date: Tue, 4 Oct 2022 22:39:57 +0200 Subject: [PATCH] with memory db --- como_core/src/items/mod.rs | 9 ++- como_core/src/projects/mod.rs | 9 ++- como_domain/src/item/mod.rs | 3 +- como_domain/src/item/queries.rs | 13 ++++ como_domain/src/projects/mod.rs | 4 +- como_domain/src/projects/queries.rs | 14 ++++ como_gql/src/graphql.rs | 69 +++++++++++++++-- como_gql/src/items.rs | 76 +++++++++++++++++++ como_gql/src/lib.rs | 2 + como_gql/src/projects.rs | 18 +++++ como_infrastructure/src/register.rs | 7 +- .../src/services/item_service.rs | 68 ++++++++++++++++- .../src/services/project_service.rs | 48 +++++++++++- 13 files changed, 326 insertions(+), 14 deletions(-) create mode 100644 como_domain/src/item/queries.rs create mode 100644 como_domain/src/projects/queries.rs create mode 100644 como_gql/src/items.rs create mode 100644 como_gql/src/projects.rs diff --git a/como_core/src/items/mod.rs b/como_core/src/items/mod.rs index 7ceebc2..0d1e940 100644 --- a/como_core/src/items/mod.rs +++ b/como_core/src/items/mod.rs @@ -1,11 +1,18 @@ use std::sync::Arc; use async_trait::async_trait; -use como_domain::item::{requests::CreateItemDto, responses::CreatedItemDto}; +use como_domain::item::{ + queries::{GetItemQuery, GetItemsQuery}, + requests::CreateItemDto, + responses::CreatedItemDto, + ItemDto, +}; pub type DynItemService = Arc; #[async_trait] pub trait ItemService { async fn add_item(&self, item: CreateItemDto) -> anyhow::Result; + async fn get_item(&self, query: GetItemQuery) -> anyhow::Result; + async fn get_items(&self, query: GetItemsQuery) -> anyhow::Result>; } diff --git a/como_core/src/projects/mod.rs b/como_core/src/projects/mod.rs index a203790..4c7b737 100644 --- a/como_core/src/projects/mod.rs +++ b/como_core/src/projects/mod.rs @@ -1,8 +1,15 @@ use std::sync::Arc; use async_trait::async_trait; +use como_domain::projects::{ + queries::{GetProjectQuery, GetProjectsQuery}, + ProjectDto, +}; pub type DynProjectService = Arc; #[async_trait] -pub trait ProjectService {} +pub trait ProjectService { + async fn get_project(&self, query: GetProjectQuery) -> anyhow::Result; + async fn get_projects(&self, query: GetProjectsQuery) -> anyhow::Result>; +} diff --git a/como_domain/src/item/mod.rs b/como_domain/src/item/mod.rs index 46edd86..26e0a6e 100644 --- a/como_domain/src/item/mod.rs +++ b/como_domain/src/item/mod.rs @@ -1,3 +1,4 @@ +pub mod queries; pub mod requests; pub mod responses; @@ -13,7 +14,7 @@ pub enum ItemState { Deleted, } -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, InputObject, SimpleObject)] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, InputObject)] pub struct ItemDto { pub id: Uuid, pub title: String, diff --git a/como_domain/src/item/queries.rs b/como_domain/src/item/queries.rs new file mode 100644 index 0000000..c0f8aeb --- /dev/null +++ b/como_domain/src/item/queries.rs @@ -0,0 +1,13 @@ +use async_graphql::InputObject; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, InputObject)] +pub struct GetItemQuery { + pub item_id: Uuid, +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, InputObject)] +pub struct GetItemsQuery { + pub user_id: Uuid, +} diff --git a/como_domain/src/projects/mod.rs b/como_domain/src/projects/mod.rs index ba68ade..daec4e4 100644 --- a/como_domain/src/projects/mod.rs +++ b/como_domain/src/projects/mod.rs @@ -1,10 +1,12 @@ +pub mod queries; pub mod requests; pub mod responses; +use async_graphql::{InputObject, SimpleObject}; use serde::{Deserialize, Serialize}; use uuid::Uuid; -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, InputObject, SimpleObject)] pub struct ProjectDto { pub id: Uuid, pub name: String, diff --git a/como_domain/src/projects/queries.rs b/como_domain/src/projects/queries.rs new file mode 100644 index 0000000..52e111f --- /dev/null +++ b/como_domain/src/projects/queries.rs @@ -0,0 +1,14 @@ +use async_graphql::InputObject; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, InputObject)] +pub struct GetProjectQuery { + pub project_id: Option, + pub item_id: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, InputObject)] +pub struct GetProjectsQuery { + pub user_id: Uuid, +} diff --git a/como_gql/src/graphql.rs b/como_gql/src/graphql.rs index 6cf9530..0b6fa6b 100644 --- a/como_gql/src/graphql.rs +++ b/como_gql/src/graphql.rs @@ -1,8 +1,21 @@ use async_graphql::{Context, EmptySubscription, Object, Schema}; -use como_domain::item::{requests::CreateItemDto, responses::CreatedItemDto}; +use como_domain::{ + item::{ + queries::{GetItemQuery, GetItemsQuery}, + requests::CreateItemDto, + responses::CreatedItemDto, + ItemDto, + }, + projects::{ + queries::{GetProjectQuery, GetProjectsQuery}, + ProjectDto, + }, +}; use como_infrastructure::register::ServiceRegister; +use crate::items::{CreatedItem, Item}; + pub type ComoSchema = Schema; pub struct MutationRoot; @@ -49,12 +62,14 @@ impl MutationRoot { &self, ctx: &Context<'_>, item: CreateItemDto, - ) -> anyhow::Result { + ) -> anyhow::Result { let services_register = ctx.data_unchecked::(); let created_item = services_register.item_service.add_item(item).await?; - Ok(created_item) + Ok(CreatedItem { + id: created_item.id, + }) } } @@ -62,7 +77,51 @@ pub struct QueryRoot; #[Object] impl QueryRoot { - async fn hello(&self, _ctx: &Context<'_>) -> String { - "hello".into() + // Items + async fn get_item(&self, ctx: &Context<'_>, query: GetItemQuery) -> anyhow::Result { + let item = ctx + .data_unchecked::() + .item_service + .get_item(query) + .await?; + + Ok(Item::from(item)) + } + + async fn get_items( + &self, + ctx: &Context<'_>, + query: GetItemsQuery, + ) -> anyhow::Result> { + let items = ctx + .data_unchecked::() + .item_service + .get_items(query) + .await?; + + Ok(items.iter().map(|i| Item::from(i.clone())).collect()) + } + + // Projects + async fn get_project( + &self, + ctx: &Context<'_>, + query: GetProjectQuery, + ) -> anyhow::Result { + ctx.data_unchecked::() + .project_service + .get_project(query) + .await + } + + async fn get_projects( + &self, + ctx: &Context<'_>, + query: GetProjectsQuery, + ) -> anyhow::Result> { + ctx.data_unchecked::() + .project_service + .get_projects(query) + .await } } diff --git a/como_gql/src/items.rs b/como_gql/src/items.rs new file mode 100644 index 0000000..61f25bc --- /dev/null +++ b/como_gql/src/items.rs @@ -0,0 +1,76 @@ +use async_graphql::{Context, Object}; +use como_domain::{ + item::{queries::GetItemQuery, ItemDto, ItemState}, + projects::queries::GetProjectQuery, +}; +use como_infrastructure::register::ServiceRegister; +use uuid::Uuid; + +use crate::projects::Project; + +pub struct CreatedItem { + pub id: Uuid, +} + +#[Object] +impl CreatedItem { + pub async fn item(&self, ctx: &Context<'_>) -> anyhow::Result { + let item = ctx + .data_unchecked::() + .item_service + .get_item(GetItemQuery { item_id: self.id }) + .await?; + + Ok(item.into()) + } +} + +pub struct Item { + pub id: Uuid, + pub title: String, + pub description: Option, + pub state: ItemState, +} + +#[Object] +impl Item { + pub async fn id(&self, _ctx: &Context<'_>) -> anyhow::Result { + return Ok(self.id); + } + + pub async fn title(&self, _ctx: &Context<'_>) -> anyhow::Result { + return Ok(self.title.clone()); + } + + pub async fn description(&self, _ctx: &Context<'_>) -> anyhow::Result> { + return Ok(self.description.clone()); + } + + pub async fn state(&self, _ctx: &Context<'_>) -> anyhow::Result { + return Ok(self.state); + } + + pub async fn project(&self, ctx: &Context<'_>) -> anyhow::Result { + let project = ctx + .data_unchecked::() + .project_service + .get_project(GetProjectQuery { + item_id: Some(self.id), + project_id: None, + }) + .await?; + + Ok(project.into()) + } +} + +impl From for Item { + fn from(dto: ItemDto) -> Self { + Self { + id: dto.id, + title: dto.title, + description: dto.description, + state: dto.state, + } + } +} diff --git a/como_gql/src/lib.rs b/como_gql/src/lib.rs index 26783c5..6dcd236 100644 --- a/como_gql/src/lib.rs +++ b/como_gql/src/lib.rs @@ -9,6 +9,8 @@ use async_graphql::http::{playground_source, GraphQLPlaygroundConfig}; use graphql::ComoSchema; pub mod graphql; +mod items; +mod projects; pub async fn graphql_handler( schema: Extension, diff --git a/como_gql/src/projects.rs b/como_gql/src/projects.rs new file mode 100644 index 0000000..12efea2 --- /dev/null +++ b/como_gql/src/projects.rs @@ -0,0 +1,18 @@ +use async_graphql::SimpleObject; +use como_domain::projects::ProjectDto; +use uuid::Uuid; + +#[derive(SimpleObject)] +pub struct Project { + pub id: Uuid, + pub name: String, +} + +impl From for Project { + fn from(dto: ProjectDto) -> Self { + Self { + id: dto.id, + name: dto.name, + } + } +} diff --git a/como_infrastructure/src/register.rs b/como_infrastructure/src/register.rs index ceac362..504dcfb 100644 --- a/como_infrastructure/src/register.rs +++ b/como_infrastructure/src/register.rs @@ -7,7 +7,8 @@ use crate::{ configs::AppConfig, database::ConnectionPool, services::{ - item_service::DefaultItemService, project_service::DefaultProjectService, + item_service::{DefaultItemService, MemoryItemService}, + project_service::{DefaultProjectService, MemoryProjectService}, user_service::DefaultUserService, }, }; @@ -23,8 +24,8 @@ impl ServiceRegister { pub fn new(pool: ConnectionPool, _config: Arc) -> Self { info!("creating services"); - let item_service = Arc::new(DefaultItemService::new()) as DynItemService; - let project_service = Arc::new(DefaultProjectService::new()) as DynProjectService; + let item_service = Arc::new(MemoryItemService::new()) as DynItemService; + let project_service = Arc::new(MemoryProjectService::new()) as DynProjectService; let user_service = Arc::new(DefaultUserService::new(pool.clone())) as DynUserService; info!("services created succesfully"); diff --git a/como_infrastructure/src/services/item_service.rs b/como_infrastructure/src/services/item_service.rs index ea6b32a..c5faf65 100644 --- a/como_infrastructure/src/services/item_service.rs +++ b/como_infrastructure/src/services/item_service.rs @@ -1,6 +1,17 @@ +use std::{ + collections::HashMap, + sync::{Arc, Mutex}, +}; + use axum::async_trait; use como_core::items::ItemService; -use como_domain::item::{requests::CreateItemDto, responses::CreatedItemDto}; +use como_domain::item::{ + queries::{GetItemQuery, GetItemsQuery}, + requests::CreateItemDto, + responses::CreatedItemDto, + ItemDto, +}; +use uuid::Uuid; pub struct DefaultItemService {} @@ -15,4 +26,59 @@ impl ItemService for DefaultItemService { async fn add_item(&self, _item: CreateItemDto) -> anyhow::Result { todo!() } + + async fn get_item(&self, _query: GetItemQuery) -> anyhow::Result { + todo!() + } + + async fn get_items(&self, _query: GetItemsQuery) -> anyhow::Result> { + todo!() + } +} + +pub struct MemoryItemService { + item_store: Arc>>, +} + +impl MemoryItemService { + pub fn new() -> Self { + Self { + item_store: Arc::new(Mutex::new(HashMap::new())), + } + } +} + +#[async_trait] +impl ItemService for MemoryItemService { + async fn add_item(&self, create_item: CreateItemDto) -> anyhow::Result { + if let Ok(mut item_store) = self.item_store.lock() { + let item = ItemDto { + id: Uuid::new_v4(), + title: create_item.name, + description: None, + state: como_domain::item::ItemState::Created, + }; + + item_store.insert(item.id.to_string(), item.clone()); + + return Ok(item); + } else { + Err(anyhow::anyhow!("could not unlock item_store")) + } + } + + async fn get_item(&self, query: GetItemQuery) -> anyhow::Result { + if let Ok(item_store) = self.item_store.lock() { + let item = item_store + .get(&query.item_id.to_string()) + .ok_or(anyhow::anyhow!("could not find item"))?; + return Ok(item.clone()); + } else { + Err(anyhow::anyhow!("could not unlock item_store")) + } + } + + async fn get_items(&self, _query: GetItemsQuery) -> anyhow::Result> { + todo!() + } } diff --git a/como_infrastructure/src/services/project_service.rs b/como_infrastructure/src/services/project_service.rs index 23e7384..02f9004 100644 --- a/como_infrastructure/src/services/project_service.rs +++ b/como_infrastructure/src/services/project_service.rs @@ -1,4 +1,12 @@ +use std::{collections::HashMap, sync::Arc}; + +use axum::async_trait; use como_core::projects::ProjectService; +use como_domain::projects::{ + queries::{GetProjectQuery, GetProjectsQuery}, + ProjectDto, +}; +use tokio::sync::Mutex; pub struct DefaultProjectService {} @@ -8,4 +16,42 @@ impl DefaultProjectService { } } -impl ProjectService for DefaultProjectService {} +#[async_trait] +impl ProjectService for DefaultProjectService { + async fn get_project(&self, _query: GetProjectQuery) -> anyhow::Result { + todo!() + } + async fn get_projects(&self, _query: GetProjectsQuery) -> anyhow::Result> { + todo!() + } +} + +pub struct MemoryProjectService { + project_store: Arc>>, +} + +impl MemoryProjectService { + pub fn new() -> Self { + Self { + project_store: Arc::new(Mutex::new(HashMap::new())), + } + } +} + +#[async_trait] +impl ProjectService for MemoryProjectService { + async fn get_project(&self, query: GetProjectQuery) -> anyhow::Result { + let ps = self.project_store.lock().await; + if let Some(item_id) = query.item_id { + Ok(ps + .get(&item_id.to_string()) + .ok_or(anyhow::anyhow!("could not find project"))? + .clone()) + } else { + Err(anyhow::anyhow!("could not find project")) + } + } + async fn get_projects(&self, _query: GetProjectsQuery) -> anyhow::Result> { + todo!() + } +}